DEV Community

Devil Scrapes
Devil Scrapes

Posted on

Yandex Maps Places Scraper: why two pages of 25 give you 49 places

Quick answer

The Yandex Maps Places Scraper turns a Yandex Maps search such as cafe in Moscow into a deduplicated table of places: name, address, latitude and longitude, rating, rating and review counts, phone numbers, websites, categories and opening hours, plus the page and rank each place appeared at. Yandex Maps is the main local-business directory across Russia and the CIS, and it has no public places API. Pricing is pay-per-result, $0.20 per run plus $0.004 per place, $4.20 per 1,000 places.

Does Yandex Maps have a places API?

Not one that returns business listings for search. Yandex's geocoder and static-map APIs turn addresses into coordinates and render map tiles, but the "find me every pharmacy in this city with its phone number and rating" data lives only in the Maps web app. That app talks to its own internal endpoints, and every request it makes carries a signature computed from the exact query string. Change a parameter, a parameter's order or how a space is encoded, and the signature no longer matches. We rebuild that signing step for every page, so you just give us a query and a city.

Why do two pages of 25 give you 49 places, not 50?

This is the detail that decides whether your counts are honest. Yandex serves 25 places per page, but the pages overlap at the seam: the last place on page 1 can reappear as the first place on page 2. Some result slots are not businesses at all but curated "collection" cards. Count raw items and you over-report. Fail to dedupe and the same cafe lands in your CRM twice.

Yandex Maps search pages overlap at the seam, so two pages of 25 typically yield 49 unique places, not 50.

So we dedupe by Yandex's organization id within each search, skip the non-business items, record the page each place was first seen on and its position after dedupe, and fetch a couple of extra pages when needed so maxResults: 50 really returns 50 places when Yandex has them.

What else we normalise

  • Coordinates two ways. Yandex serves [lon, lat], which trips up everyone who expects latitude first. We keep coordinates exactly as served and also split out named lat and lon fields.
  • Opening hours two ways. workingTime is the human string ("Mon-Thu 12:00–02:00"). workingHours is the structured per-weekday version for code, with from and to hours and minutes.
  • Ratings rounded to two decimals, with ratingCount and reviewCount kept separate, because they are different numbers.

What the Actor gives you

One row per place, 20 fields: id, name, address, lat, lon, coordinates, rating, ratingCount, reviewCount, phones, urls, categories, workingTime, workingHours, sourceUrl, query, geoId, page, position and scrapedAt.

{
  "id": "243088808182",
  "name": "Alkobufet",
  "address": "Moscow, Sretenka Street, 36",
  "lat": 55.771647,
  "lon": 37.632628,
  "coordinates": [37.632628, 55.771647],
  "rating": 4.9,
  "ratingCount": 2757,
  "reviewCount": 1321,
  "phones": ["+79152776884"],
  "urls": ["https://taplink.cc/alkobufet.shashlik"],
  "categories": ["Cafe", "the glass room"],
  "workingTime": "Mon-Thu 12:00–02:00; Fri,Sat 12:00–05:00; Sun 12:00–02:00",
  "sourceUrl": "https://yandex.com/maps/org/alkobufet_shashlychnaya/243088808182",
  "query": "cafe",
  "geoId": 213,
  "page": 1,
  "position": 1,
  "scrapedAt": "2026-10-09T00:00:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Input: searches, each one an object ({"query": "cafe", "geoId": 213, "city": "moscow"}), a pasted Yandex Maps search URL, or the short text form cafe | 213 moscow. Up to 50 searches per run and maxResults up to 500 places per search.

Honest limitations 🚧

Review text, photos and per-place detail pages are not included: you get the rating and the counts. Moscow is built in; any other city needs its geoId and city slug, both visible in the Yandex Maps URL (or just paste the URL). English (US) is the supported locale for now, and place names come back as Yandex serves them. A search with no matches is a successful run that costs only the start fee.

FAQ

Do I need a Yandex account or API key?
No. The Actor reads the same public search the Maps web app uses.

What about blocks and captchas?
That's our job. We rotate real-browser TLS fingerprints (Firefox and Safari profiles) through curl-cffi, use a fresh Apify Proxy session for every search and on every block, pace requests at least three seconds apart, and retry with exponential backoff on 408, 429 and 503, up to 5 attempts per page.

How do I scrape a city other than Moscow?
Open the search on yandex.com/maps and paste the URL. It contains the geoId and city slug, and the Actor reads both from it.

How does pricing work?
$0.20 per run plus $0.004 per unique place: $4.20 per 1,000 places.

→ Yandex Maps Places Scraper on Apify


Built by Devil Scrapes. We handle the request signing, the fingerprints, the proxies and the retries, and we count unique places, not raw slots. 😈

Top comments (0)