Milanuncios (Segunda Mano) Scraper - Ads, Prices, Province avatar

Milanuncios (Segunda Mano) Scraper - Ads, Prices, Province

Pricing

$1.00 / 1,000 listings

Go to Apify Store
Milanuncios (Segunda Mano) Scraper - Ads, Prices, Province

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

Lantern Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Categories

Security

Limited permissions

Share

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
}
FieldWhat it does
searchQueriesSpanish keywords, one per line. Each is searched separately and its rows are labelled with it.
searchUrlsMilanuncios 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.
provinceProvince slug as Milanuncios spells it in its own /anuncios-en-<slug>/ links: madrid, barcelona, valencia, baleares, guipuzcoa, vizcaya, tenerife. Narrows searchQueries.
maxListingsUpper bound on listing rows for the whole run. Default 100.
maxListingsPerInputOptional share of that budget per keyword or URL, so one input cannot eat the run.
maxUpstreamRequestsOptional hard ceiling on requests to Milanuncios. Left empty, one is derived from your input — it is never unbounded.
proxyConfigurationDefaults 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:

partialReasonWhat happened
listing_limit_reachedYour maxListings or maxListingsPerInput cut this input short.
upstream_request_capThe run's request ceiling was reached while on this input.
blockedMilanuncios served its interstitial from every proxy session tried.
search_rejectedMilanuncios rejected the search itself and returned its own error instead of a result list.
url_not_foundThe URL does not exist — Milanuncios 404s it or redirects it to its homepage.
page_not_renderedA 200 arrived with no result payload in it.
upstream_errorThe request failed for another reason.
not_collectedThe 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. sellerType keeps 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 baleares and on guipuzcoa, 41 of 41 on madrid. Every row carries its own true province, 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: 0 is what Milanuncios sends for an ad that names no price; it is passed through rather than guessed at.