Milanuncios (Segunda Mano) Scraper - Ads, Prices, Province
Pricing
$1.00 / 1,000 listings
Milanuncios (Segunda Mano) Scraper - Ads, Prices, Province
Collect public Milanuncios ads from any category, province or keyword: ad ID, title, price in EUR, province, city, category path, publish time and seller type. No login, no cookies, no personal seller data. Rows are deduplicated; empty and partial inputs are never charged.
Pricing
$1.00 / 1,000 listings
Rating
0.0
(0)
Developer
Lantern Lab
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Security
Limited permissionsShare
Milanuncios Scraper — public Spanish classified ads, by keyword, category or province
Collect public ads from Milanuncios, Spain's largest classifieds site, from any category, filter, province or keyword you can open in a browser. Every row carries the ad's own ID, title, price in EUR, province, city, full category path, publish time, seller type and the ad URL.
What you get per ad: listingId · title · price (EUR) · previousPrice and the
price-drop badge · province · city · region · category and the whole
categoryPath · publishedAt and updatedAt (the platform's own times) · specs the
seller filled in · imageCount · url · sellerType (private / professional) ·
sellType (supply / demand) · collectedAt (when we read it).
Price: pay per listing — you are charged for listing rows only. A search that returns nothing, a search that was cut short, and the run summary are all free rows, so you never pay for a result you did not get.
No login, no cookies, no account. Only data a logged-out visitor sees on the result page.
Input
{"searchQueries": ["bicicleta eléctrica"],"province": "madrid","maxListings": 200}
Or point it at a result page you already have — any category, filter or sort:
{"searchUrls": ["https://www.milanuncios.com/coches-de-segunda-mano-en-madrid/","https://www.milanuncios.com/motos-de-segunda-mano/?precio_hasta=3000"],"maxListings": 500,"maxListingsPerInput": 100}
| Field | What it does |
|---|---|
searchQueries | Spanish keywords, one per line. Each is searched separately and its rows are labelled with it. |
searchUrls | Milanuncios result-list URLs copied from the address bar. Every filter in the URL is kept. A URL copied from page 3 starts at page 3. |
province | Province slug as Milanuncios spells it in its own /anuncios-en-<slug>/ links: madrid, barcelona, valencia, baleares, guipuzcoa, vizcaya, tenerife. Narrows searchQueries. |
maxListings | Upper bound on listing rows for the whole run. Default 100. |
maxListingsPerInput | Optional share of that budget per keyword or URL, so one input cannot eat the run. |
maxUpstreamRequests | Optional hard ceiling on requests to Milanuncios. Left empty, one is derived from your input — it is never unbounded. |
proxyConfiguration | Defaults to Apify Proxy residential with a Spanish exit IP, which is what this Actor is measured on. |
province narrows keywords only, and takes the slug Milanuncios itself uses —
lowercase, unaccented Castilian, one word for almost every province. A slug the site
does not have is reported as url_not_found, never quietly searched across all of Spain.
For searchUrls put the province in the URL itself: Milanuncios keeps it inside the path
of each category page and the shape differs per category
(/coches-de-segunda-mano-en-madrid/, /pisos-en-barcelona-barcelona/), so copy the
real link rather than building one. Setting province with only URLs is rejected rather
than silently ignored.
Output
One row per ad:
{"recordType": "listing","listingId": "616474771","title": "Bicicleta eléctrica de montaña","price": 1900,"currency": "EUR","previousPrice": 2000,"priceDropLabel": "- 5 %","province": "Madrid","city": "Alcorcón","region": "Madrid","category": "Bicicletas de montaña","categoryPath": ["Deportes y náutica", "Deportes", "Bicicletas", "Bicicletas de montaña"],"publishedAt": "2026-09-24T18:41:49Z","updatedAt": "2026-10-24T18:37:05Z","specs": [{ "name": "color", "value": "verde claro" }],"imageCount": 2,"url": "https://www.milanuncios.com/bicicletas-montana-de-segunda-mano/bicicleta-electrica-de-montana-616474771.htm","sellerType": "private","sellType": "supply","query": "bicicleta eléctrica","sourceUrl": "https://www.milanuncios.com/anuncios-en-madrid/?s=bicicleta+el%C3%A9ctrica","page": 1,"rank": 1,"partial": false,"partialReason": null,"collectedAt": "2026-10-25T09:12:44.118Z"}
Plus one free input_status row per keyword or URL, saying what it returned and whether
that is all there was:
{"recordType": "input_status","query": "bicicleta eléctrica","listingsReturned": 41,"duplicatesSkipped": 0,"pagesFetched": 1,"totalAds": 6923,"totalAdsRelation": "eq","lastPageOffered": 169,"partial": false,"partialReason": null,"statusText": "Collected 41 listing(s) for this input; the result list was followed to its end or to the limits you set."}
And RUN_SUMMARY as the last dataset row and under that key in the run's key-value
store: rows collected and charged, duplicates skipped, pages read, empty inputs, partial
inputs by reason, requests sent against the ceiling, and bytes received.
partial: true never means "no ads". It means that input's results are incomplete,
and partialReason says why:
partialReason | What happened |
|---|---|
listing_limit_reached | Your maxListings or maxListingsPerInput cut this input short. |
upstream_request_cap | The run's request ceiling was reached while on this input. |
blocked | Milanuncios served its interstitial from every proxy session tried. |
search_rejected | Milanuncios rejected the search itself and returned its own error instead of a result list. |
url_not_found | The URL does not exist — Milanuncios 404s it or redirects it to its homepage. |
page_not_rendered | A 200 arrived with no result payload in it. |
upstream_error | The request failed for another reason. |
not_collected | The run stopped before reaching this input. |
An input that genuinely has no results is written with partial: false and
listingsReturned: 0.
Limits and things to know
- Spanish residential IPs only. Milanuncios answers a datacenter IP with a 403
"Pardon Our Interruption" interstitial. The default proxy setting handles this;
changing it will make runs report
partialReason: "blocked". - Pagination depth. Milanuncios offers at most 200 pages (~8,200 ads) per result
list and caps its own reported total at 10,000 —
totalAdsRelation: "gte"means the count is a lower bound. To go deeper, split the search by province, category or a price filter. - No personal data. No seller name, no phone number, no email and no free-text ad
description is collected.
sellerTypekeeps the private/professional distinction. A professional ad's display name is skipped too, because Milanuncios puts a person's own name there as often as a shop's. - Result pages only. This Actor reads the fields Milanuncios renders into its result lists; it does not open each ad's own page, so ad-detail-only fields are not included.
- A province page is not a hard filter. Milanuncios mixes a couple of nationally
promoted ads into a province result list — measured 39 of 41 on
balearesand onguipuzcoa, 41 of 41 onmadrid. Every row carries its own trueprovince, so filter on the field rather than trusting the page. - Deduplication is per run. An ad matching several keywords is written and charged once. Across two separate runs you will see it twice.
- Prices are as stated.
price: 0is what Milanuncios sends for an ad that names no price; it is passed through rather than guessed at.