Half the Google Maps scraping tutorials on the internet are broken. While researching this post we ran the code from a top-ranking article, and the CSS selectors it relies on stopped existing years ago. The Reddit thread ranking #1 for this exact question: six years old, no working answer.
So we wrote the tutorial we wanted to find: a real answer to how to scrape data from Google Maps using Python. Everything below ran successfully this month, on the current interface, and pulled real data from 42 Austin coffee shops. You get two complete methods, and you can pick your fight:
Method 1: Selenium (DIY)
A full browser-automation scraper you build step by step: search, infinite scroll, card parsing, detail pages, CSV. Free, educational, and yours to maintain.
Method 2: API (one request)
The same data, plus fields Selenium can't reach, in about 20 lines of Python. If you're on a deadline, jump straight to the API method →
This guide takes you from the first pip install to a clean CSV: names, ratings, categories, addresses, phone numbers, and websites. We run scraping infrastructure for a living at FlyByAPIs, and the DIY section is honest about what breaks, because we’ve broken all of it ourselves.
42
Businesses scraped in our test run
~2 min
Selenium test run (42 + 5 details)
200
Results per API request
60
Max results, official Places API
In short: Google Maps renders everything with JavaScript, so you need Selenium to drive a real browser, scroll the results feed, and parse each card. That works, and we show every line, but it’s slow and fragile at scale, which is why the second method uses the FlyByAPIs Google Maps scraper API that returns up to 200 structured results per request. All the code is on GitHub: flybyapis/blog-web-scraping-code → scrape-google-maps-python . Clone it and run it before you read another word.
Why Google Maps is harder to scrape than a normal website
Open a Google Maps search, hit view-source, and look for a business name. It’s not there. The HTML your browser receives is a nearly empty shell, and every listing you see gets rendered by JavaScript after the page loads.
That single fact kills the classic requests + BeautifulSoup approach that works on static sites (the one we use in our general Python web scraping guide
). No JavaScript engine, no data.
Three more obstacles stack on top:
Infinite scroll instead of pagination
There is no page 2. Results load as you scroll a side panel, about 6 at a time, and stop at a hidden "end of list" marker.
Obfuscated, rotating CSS classes
Class names like Nv2PK are machine-generated and change without notice. Every tutorial hardcoding them has an expiry date.
Anti-bot detection
Google fingerprints automation and rate-limits IPs. Works fine for 50 pages, then the CAPTCHAs start.
Our Selenium scraper deals with the first two properly, and we’ll be straight with you about the third. Let’s build it.
How to scrape data from Google Maps using Python and Selenium
The plan: drive a real Chrome browser, search Google Maps, scroll the results feed until we have enough businesses, parse each card, then visit individual place pages for phone numbers and websites. Six steps, all runnable.
Step 1: Set up Selenium and ChromeDriver
You need Python 3.10+ and two packages. Selenium 4.6+ can resolve drivers on its own via Selenium Manager, but we still install webdriver-manager because it pins the ChromeDriver download explicitly, which behaves more predictably on CI:
| |
Now the driver factory. The flags matter: --headless=new is the current headless mode (the old one is detectable and renders differently), and a realistic user agent avoids the most basic bot filter:
| |
Step 2: Load the search and handle the consent wall
Google Maps accepts search queries directly in the URL, which saves us from automating the search box. One detail that broke our first test run: Google localizes the interface based on your IP and account, and our results came back in Catalan. Force hl=en or your parsing will fail in fun ways:
| |
Those last five lines are a quick smoke test to confirm the page loads for you. The final script’s main() in Step 6 repeats them properly, so drop them before assembling the full file (or you’ll launch two Chrome instances).
Selector strategy that survives redesigns:
We never use Google's obfuscated class names. Everything below targets semantic attributes: div[role="feed"], a[href*="/maps/place/"], aria-label. Google changes cosmetic classes constantly but rarely touches accessibility attributes, because screen readers depend on them.
Step 3: Beat infinite scroll (the part every tutorial skips)
A fresh search shows about 6 to 12 results. The rest only exist after you scroll the results panel, and this is where most tutorials quietly stop. The trick is that you must scroll the feed element, not the page: window.scrollTo does nothing on Google Maps.
| |
Three exit conditions, and all of them matter in practice:
- The end-of-list marker catches exhausted searches where fewer businesses exist than you asked for.
- The target count stops you from collecting more than you need.
- The stale counter saves you when Google throttles loading and the feed just stops growing.
In our test, reaching 40 coffee shops took 8 scroll rounds, about 20 seconds. Each round loads roughly 6 new businesses, and one search only goes so far: the feed exhausts itself at roughly 100 to 120 results, so a 5,000-business list means dozens of separate queries, each with its own scrolling session.
Step 4: Parse the result cards
Each card in the feed is a div containing a place link. The business name sits in the link’s aria-label, the star rating in a span[role="img"], and category plus street address share a text line separated by a middle dot:
| |
Notice what’s not here: review counts. The current list view doesn’t render them in a parseable way, and review text lives behind another click and another infinite scroll. This is the point where DIY costs start compounding, and where the business reviews endpoint of a Google Maps API turns a scraping subproject into one GET request.
Step 5: Visit each place page for phone and website
The cards give you name, rating, category, and street. Phone numbers and websites need a visit to each place page. The good news: place pages use data-item-id attributes, which are semantic and stable:
| |
The bad news is the cost. Every business is now a full page load, roughly 5 to 6 seconds each. Enriching 100 businesses adds 10 minutes of browser time to your run, and 10,000 businesses is a 16-hour job, per search, per city.
Step 6: Write the CSV and run it
| |
Here’s real output from our verification run this month:
| |
It works! A real scraper, running against the live site, with names, ratings, categories, addresses, phones, and websites in a spreadsheet. If you only need a one-off list of 50 businesses, you can genuinely stop here.
Why this scraper will eventually break (and when)
We’d be lying if we ended the DIY section on “it works!”. We run scraping infrastructure for thousands of daily requests, and here is what happens to this exact script at scale.
Google will flag your IP. Past a few hundred page loads a day from one IP, you start seeing CAPTCHAs and empty responses. We wrote a whole post on why web scrapers get blocked , but the short version: fingerprinting plus rate patterns, and residential proxies to work around it start around $50/month and climb fast.
Selectors rot silently. Our aria-based selectors are the most durable choice available, but Google ships UI experiments constantly: the GeeksforGeeks tutorial ranking on page one for this keyword still references class names from an interface that no longer exists.
"Nobody emails you when your scraper dies; your pipeline just delivers zero rows."
The data has holes. No review counts in the list view, no emails, no opening-hours structure without more parsing, no historical data. Each missing field is another sub-scraper to build and babysit.
Rule of thumb from our own migrations:
A DIY Maps scraper is the right call below ~500 businesses per month and one target country. Above that, browser time, proxy bills, and selector maintenance quietly overtake the cost of a Google Maps extractor API subscription.
This same trade-off applies anywhere serious anti-bot walls exist. We’ve documented the identical pattern scraping product data behind Amazon’s defenses with our Amazon scraping API , and on search results pages with our Google Search API . Build the toy version yourself, buy the production version.
The API method: the same data in one request
Method 2. Everything the Selenium scraper collected in minutes of browser time, plus the fields it couldn’t reach, from one HTTP request. It comes back in seconds.
We built the FlyByAPIs Google Maps extractor because we got tired of maintaining exactly the script you just read. Grab a free key from the Google Maps API on RapidAPI (100 requests/month, no credit card), and you’re two minutes from structured data.
| |
That’s the entire scraper. No ChromeDriver, no scrolling loop, no consent wall, no selectors to maintain. Each business in data comes back as rich JSON:
| |
Notice reviews_count is just there, the field our Selenium scraper couldn’t reach at all. Compare the pagination story too: instead of scrolling and praying, you page deterministically with offset until the API stops returning new rows. Our CSV export tutorial builds a complete paginated collector in about 60 lines if that’s your end goal.
Going deeper: details and reviews
Two more endpoints cover what would have been entire Selenium subprojects. Pass any google_id from the search results:
| |
If you’re doing lead generation across borders, review text arrives in whatever language customers wrote it; our translation API normalizes it in the same pipeline. And teams enriching those leads further usually join in firmographics from our Crunchbase scraper API or hiring signals from the Jobs Search API .
100 requests/month free · No credit card required
Selenium vs API vs official Places API: the honest comparison
Three ways to get this data, three very different bills. The official Google Places API deserves a mention because everyone asks: it’s legitimate and reliable, but Text Search caps out at 60 results per query and pricing runs about $32 per 1,000 requests before per-field detail charges.
| Factor | Selenium DIY | FlyByAPIs extractor | Official Places API |
|---|---|---|---|
| Results per query | Until end of list (slow) | 200/request + offset paging | 60 max |
| Time for 1,000 businesses | Hours: ~10 searches, each scrolled + detail visits | 5 requests, seconds | ~17 sub-area queries + grid logic |
| Reviews + review text | Separate scraper to build | Included endpoint | 5 most recent only |
| Maintenance | Yours, forever | Provider's problem | None |
| Cost at 10K businesses/mo | Proxies $50+/mo + your hours | ~50 requests, entry plan | ~$32/1K searches + per-field detail charges |
| Blocking risk | High at scale | Handled server-side | None |
Do you see the pattern? The official API is safe but capped at 60 results, which disqualifies it for any serious lead list, and Selenium is free until your time and proxies aren’t. The extractor route via a Google Maps data API built for scale is what’s left when you need volume, completeness, and your weekends.
Which method should you pick?
Pick Selenium
One-off lists under ~500 businesses, learning projects, or when the budget is exactly zero. You now have a working scraper for it.
Pick the API
Recurring pipelines, review data, multi-city lead generation, or anything a client is waiting on. The Google Maps business data API returns 200 results per request, reviews included, zero maintenance.
Pick the official Places API
You need Google's blessing for a consumer-facing product and 60 results per query is enough. Budget for per-field pricing.
Combine both
Prototype selectors and logic with Selenium locally, run production volume through the extractor. Same schema thinking, different engines.
Wrapping up
We started with a promise: working code, verified this month. The Selenium scraper pulled 42 real businesses with ratings, addresses, phones, and websites, and every one of its limitations is now documented instead of discovered at 2 AM. The API method got the same data, plus review counts and text, in one request.
All of it, both scrapers plus a requirements file, is ready to clone:
| |
Start with the free tier, point the Google Maps data extraction API at your city, and see what 200 structured results per request feels like after babysitting a browser.
100 requests/month free · No credit card required
P.S. If your next stop after collecting businesses is ranking data, the same “build vs buy” logic applies to search results; that story is in our SERP API comparison .
Oriol.
