How to Scrape Google Maps Search Results with TalorData

Learn how to scrape Google Maps search results with TalorData SERP API. This technical guide covers Maps parameters, Python requests, local business fields, ratings, reviews, addresses, phone numbers, websites, place IDs, coordinates, CSV export, and local SEO workflows.

talor ai
最後更新於
14 分鐘閱讀

Google Maps results are local-intent data. They show which businesses appear for a query, where they rank, how strong their reputation looks, and what contact details are visible.

If you are building local SEO tools, lead generation workflows, market research dashboards, competitor monitors, or AI agents, Google Maps data can help answer questions like:

Question

Why it matters

Which businesses appear for “dentist near me”?

Local visibility

Which competitor ranks higher around a specific coordinate?

Local SEO tracking

Which businesses have strong ratings and review counts?

Reputation analysis

Which listings have phone numbers and websites?

Lead enrichment

Which areas are crowded with competitors?

Market research

Which listings appear in multiple cities?

Expansion planning

Which local results should an AI agent recommend?

AI workflow context

In this guide, we will build a Python workflow that sends Google Maps queries to TalorData, receives structured JSON, extracts useful business fields, and exports the results to CSV.

The final workflow looks like this:

Search query + map location
   ↓
TalorData SERP API
   ↓
Google Maps results in JSON
   ↓
Parse business fields
   ↓
Normalize place data
   ↓
Export to CSV or database

What does scraping Google Maps search results mean?

In this article, “scraping Google Maps” means collecting structured Google Maps-style search results through TalorData’s SERP API.

It does not mean controlling a browser, scrolling manually, or scraping HTML from the Google Maps interface.

The goal is to collect fields such as:

Field

Example

Business name

Blue Bottle Coffee

Position

1

Rating

4.5

Review count

1,240

Category

Coffee shop

Address

123 Example St, New York

Phone number

+1 212-000-0000

Website

https://example.com

Google Maps URL

Maps listing link

Place ID / data CID

Unique place reference

Latitude / longitude

Map coordinates

Opening status

Open now / closed

Price level

$, $$, $$$

TalorData Google Maps responses are designed for local business search workflows and can include fields such as business name, place ID, address, coordinates, category, rating, review count, rank position, opening status, phone number, website, Google Maps URL, thumbnail, and price level when available.

When should you use the Google Maps SERP API?

Use Google Maps search results when your question is about local visibility.

Use case

Example

Local SEO rank tracking

Track “plumber near me” around different coordinates

Lead generation

Collect local businesses with phone and website

Competitor research

Compare ratings, reviews, and positions

Market analysis

Count businesses in a category by city

Franchise monitoring

Check brand visibility across markets

Review intelligence

Track rating and review count signals

AI agents

Feed local business options into recommendations

Google Maps rankings are location-sensitive. A query from one coordinate may return a different set of businesses than the same query a few blocks away. That is why location control matters.

Core Google Maps parameters

Start with these parameters.

Parameter

Required

Purpose

Example

engine

Yes

Select Google Maps search

google_maps

q

For search queries

Business, category, or local intent query

coffee shops

ll

Recommended for map search

Latitude, longitude, and zoom

@40.7455096,-74.0083012,14z

type

Optional

Search mode

search or place

place_id

For place lookup

Specific Google Maps place reference

ChIJ...

data_cid

For place lookup

Google CID-style place reference

123456789

google_domain

Optional

Google domain

google.com

hl

Optional

Interface language

en

gl

Optional

Country context

us

no_cache

Optional

Freshness control

true

For Google Maps requests, ll uses a coordinate format like @latitude,longitude,scale, and the Maps search type supports search-style and place-style workflows.

Search mode vs place mode

You will usually use one of two patterns.

Search mode

Use search mode when you want a list of businesses.

Examples:

coffee shops near Manhattan
dentists in Austin
hotels near JFK Airport
plumbers in Chicago
restaurants near Times Square

A search request needs a query and location context.

{
  "engine": "google_maps",
  "type": "search",
  "q": "coffee shops",
  "ll": "@40.7455096,-74.0083012,14z",
  "hl": "en",
  "gl": "us"
}

Place mode

Use place mode when you want details for one known place.

You can use a place_id or data_cid from a previous Maps result.

{
  "engine": "google_maps",
  "type": "place",
  "place_id": "ChIJExamplePlaceId",
  "hl": "en",
  "gl": "us"
}

A common workflow is:

Search query
   ↓
Get local business results
   ↓
Extract place_id or data_cid
   ↓
Request place details
   ↓
Store richer business data

Step 1: Set up your API key

Store your TalorData API key and endpoint as environment variables.View the setup guide>>

export TALORDATA_API_KEY="your_api_key_here"
export TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"

On Windows PowerShell:

setx TALORDATA_API_KEY "your_api_key_here"
setx TALORDATA_SERP_ENDPOINT "your_talordata_serp_endpoint_here"

Install Python dependencies:

pip install requests pandas

Step 2: Create a reusable Python client

This function sends a Google Maps search request and returns JSON.

Adjust the endpoint or authentication format if your TalorData account uses a different request style.

import os
import requests
from typing import Any, Dict, Optional


TALORDATA_API_KEY = os.getenv("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = os.getenv("TALORDATA_SERP_ENDPOINT")


def fetch_google_maps(
    query: str,
    ll: str,
    hl: str = "en",
    gl: str = "us",
    google_domain: str = "google.com",
    no_cache: bool = True,
    extra_params: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
    """
    Fetch Google Maps search results with TalorData SERP API.

    ll format example:
    @40.7455096,-74.0083012,14z
    """
    if not TALORDATA_API_KEY:
        raise RuntimeError("Missing TALORDATA_API_KEY environment variable.")

    if not TALORDATA_SERP_ENDPOINT:
        raise RuntimeError("Missing TALORDATA_SERP_ENDPOINT environment variable.")

    payload: Dict[str, Any] = {
        "engine": "google_maps",
        "type": "search",
        "q": query,
        "ll": ll,
        "hl": hl,
        "gl": gl,
        "google_domain": google_domain,
        "no_cache": no_cache
    }

    if extra_params:
        payload.update(extra_params)

    headers = {
        "Authorization": f"Bearer {TALORDATA_API_KEY}",
        "Content-Type": "application/json"
    }

    response = requests.post(
        TALORDATA_SERP_ENDPOINT,
        json=payload,
        headers=headers,
        timeout=30
    )

    response.raise_for_status()
    return response.json()

Run a basic search:

if __name__ == "__main__":
    data = fetch_google_maps(
        query="coffee shops",
        ll="@40.7455096,-74.0083012,14z",
        hl="en",
        gl="us"
    )

    print(data)

Step 3: Inspect the raw response

Before writing a parser, inspect the JSON.

import json

print(json.dumps(data, indent=2, ensure_ascii=False)[:5000])

Look for result arrays such as:

local_results
maps_results
place_results
results
organic_results

The exact field name can vary by response type. Do not carve your parser into stone too early. First check the cave wall, then bring the chisel.

Step 4: Parse Google Maps results

Here is a defensive parser that checks several possible result containers and extracts common local business fields.

from typing import Any, Dict, List


def get_first_available_list(data: Dict[str, Any], keys: List[str]) -> List[Dict[str, Any]]:
    for key in keys:
        value = data.get(key)

        if isinstance(value, list):
            return value

    return []


def parse_maps_results(data: Dict[str, Any]) -> List[Dict[str, Any]]:
    items = get_first_available_list(
        data,
        keys=[
            "local_results",
            "maps_results",
            "place_results",
            "results",
            "organic_results"
        ]
    )

    rows = []

    for index, item in enumerate(items, start=1):
        gps = item.get("gps_coordinates") or {}
        links = item.get("links") or {}

        rows.append({
            "position": item.get("position", index),
            "title": item.get("title") or item.get("name"),
            "place_id": item.get("place_id"),
            "data_cid": item.get("data_cid") or item.get("cid"),
            "category": item.get("type") or item.get("category"),
            "rating": item.get("rating"),
            "review_count": item.get("reviews") or item.get("review_count"),
            "address": item.get("address"),
            "phone": item.get("phone"),
            "website": item.get("website") or links.get("website"),
            "maps_url": item.get("link") or item.get("maps_url"),
            "thumbnail": item.get("thumbnail"),
            "price_level": item.get("price") or item.get("price_level"),
            "open_state": item.get("open_state") or item.get("hours"),
            "latitude": gps.get("latitude") or item.get("latitude"),
            "longitude": gps.get("longitude") or item.get("longitude")
        })

    return rows

Use it:

data = fetch_google_maps(
    query="coffee shops",
    ll="@40.7455096,-74.0083012,14z"
)

rows = parse_maps_results(data)

for row in rows[:5]:
    print(row["position"], row["title"], row["rating"], row["review_count"])

Step 5: Save results to CSV

import pandas as pd


data = fetch_google_maps(
    query="coffee shops",
    ll="@40.7455096,-74.0083012,14z"
)

rows = parse_maps_results(data)

df = pd.DataFrame(rows)
df.to_csv("google_maps_results.csv", index=False)

print(df.head())

A CSV table may look like this:

position

title

rating

review_count

category

address

1

Example Coffee

4.6

1280

Coffee shop

123 Example St

2

Sample Cafe

4.4

760

Cafe

45 Sample Ave

3

Local Roasters

4.7

420

Coffee roasters

88 Market Rd

Step 6: Add search context

A Maps result without context is hard to compare later.

Always store the query, coordinate, language, country, and timestamp with every row.

from datetime import datetime, timezone


def add_search_context(
    rows: List[Dict[str, Any]],
    query: str,
    ll: str,
    hl: str,
    gl: str
) -> List[Dict[str, Any]]:
    collected_at = datetime.now(timezone.utc).isoformat()

    for row in rows:
        row["query"] = query
        row["ll"] = ll
        row["hl"] = hl
        row["gl"] = gl
        row["collected_at"] = collected_at

    return rows

Usage:

query = "coffee shops"
ll = "@40.7455096,-74.0083012,14z"
hl = "en"
gl = "us"

data = fetch_google_maps(query=query, ll=ll, hl=hl, gl=gl)
rows = parse_maps_results(data)
rows = add_search_context(rows, query=query, ll=ll, hl=hl, gl=gl)

pd.DataFrame(rows).to_csv("google_maps_snapshot.csv", index=False)

Now you can compare results over time.

Change

Meaning

Position changed

Local ranking changed

Rating changed

Reputation changed

Review count increased

More customer feedback

Business disappeared

Ranking or availability changed

New competitor appeared

Market movement

Website added or removed

Listing completeness changed

Step 7: Search multiple coordinates

For local SEO, one city-level search is often too broad.

A better workflow is to test the same query across a coordinate grid.

locations = [
    {
        "name": "Manhattan West",
        "ll": "@40.7455096,-74.0083012,14z"
    },
    {
        "name": "Times Square",
        "ll": "@40.758896,-73.985130,14z"
    },
    {
        "name": "Lower Manhattan",
        "ll": "@40.707491,-74.011276,14z"
    }
]

all_rows = []

for location in locations:
    data = fetch_google_maps(
        query="coffee shops",
        ll=location["ll"],
        hl="en",
        gl="us"
    )

    rows = parse_maps_results(data)

    for row in rows:
        row["grid_location"] = location["name"]

    rows = add_search_context(
        rows,
        query="coffee shops",
        ll=location["ll"],
        hl="en",
        gl="us"
    )

    all_rows.extend(rows)

pd.DataFrame(all_rows).to_csv("google_maps_grid_results.csv", index=False)

This helps you detect:

Signal

Example

Local rank variation

A cafe ranks #1 near one coordinate and #8 near another

Competitor clusters

Many competitors appear around one neighborhood

Visibility gaps

A business disappears outside a small radius

Review advantage

Competitors with stronger reviews rank more often

Expansion areas

Underserved areas with fewer strong listings

Step 8: Fetch place-level details

A search result gives you a list. A place lookup gives you a deeper look at one business.

Use place_id or data_cid from the search result.

def fetch_google_maps_place(
    place_id: Optional[str] = None,
    data_cid: Optional[str] = None,
    hl: str = "en",
    gl: str = "us",
    google_domain: str = "google.com"
) -> Dict[str, Any]:
    if not place_id and not data_cid:
        raise ValueError("Provide either place_id or data_cid.")

    payload: Dict[str, Any] = {
        "engine": "google_maps",
        "type": "place",
        "hl": hl,
        "gl": gl,
        "google_domain": google_domain
    }

    if place_id:
        payload["place_id"] = place_id

    if data_cid:
        payload["data_cid"] = data_cid

    response = requests.post(
        TALORDATA_SERP_ENDPOINT,
        json=payload,
        headers={
            "Authorization": f"Bearer {TALORDATA_API_KEY}",
            "Content-Type": "application/json"
        },
        timeout=30
    )

    response.raise_for_status()
    return response.json()

Example:

rows = parse_maps_results(data)

first_place_id = rows[0].get("place_id")
place_data = fetch_google_maps_place(place_id=first_place_id)

print(json.dumps(place_data, indent=2, ensure_ascii=False)[:3000])

Use place mode when you need to enrich a specific business after discovering it in search results.

Step 9: Build a complete script

Here is a complete script that searches Google Maps, parses local business fields, adds context, and exports to CSV.

import os
import json
import requests
import pandas as pd
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional


TALORDATA_API_KEY = os.getenv("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = os.getenv("TALORDATA_SERP_ENDPOINT")


def fetch_google_maps(
    query: str,
    ll: str,
    hl: str = "en",
    gl: str = "us",
    google_domain: str = "google.com",
    no_cache: bool = True,
    extra_params: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
    if not TALORDATA_API_KEY:
        raise RuntimeError("Missing TALORDATA_API_KEY environment variable.")

    if not TALORDATA_SERP_ENDPOINT:
        raise RuntimeError("Missing TALORDATA_SERP_ENDPOINT environment variable.")

    payload: Dict[str, Any] = {
        "engine": "google_maps",
        "type": "search",
        "q": query,
        "ll": ll,
        "hl": hl,
        "gl": gl,
        "google_domain": google_domain,
        "no_cache": no_cache
    }

    if extra_params:
        payload.update(extra_params)

    response = requests.post(
        TALORDATA_SERP_ENDPOINT,
        json=payload,
        headers={
            "Authorization": f"Bearer {TALORDATA_API_KEY}",
            "Content-Type": "application/json"
        },
        timeout=30
    )

    response.raise_for_status()
    return response.json()


def get_first_available_list(data: Dict[str, Any], keys: List[str]) -> List[Dict[str, Any]]:
    for key in keys:
        value = data.get(key)

        if isinstance(value, list):
            return value

    return []


def parse_maps_results(data: Dict[str, Any]) -> List[Dict[str, Any]]:
    items = get_first_available_list(
        data,
        keys=[
            "local_results",
            "maps_results",
            "place_results",
            "results",
            "organic_results"
        ]
    )

    rows = []

    for index, item in enumerate(items, start=1):
        gps = item.get("gps_coordinates") or {}
        links = item.get("links") or {}

        rows.append({
            "position": item.get("position", index),
            "title": item.get("title") or item.get("name"),
            "place_id": item.get("place_id"),
            "data_cid": item.get("data_cid") or item.get("cid"),
            "category": item.get("type") or item.get("category"),
            "rating": item.get("rating"),
            "review_count": item.get("reviews") or item.get("review_count"),
            "address": item.get("address"),
            "phone": item.get("phone"),
            "website": item.get("website") or links.get("website"),
            "maps_url": item.get("link") or item.get("maps_url"),
            "thumbnail": item.get("thumbnail"),
            "price_level": item.get("price") or item.get("price_level"),
            "open_state": item.get("open_state") or item.get("hours"),
            "latitude": gps.get("latitude") or item.get("latitude"),
            "longitude": gps.get("longitude") or item.get("longitude")
        })

    return rows


def add_search_context(
    rows: List[Dict[str, Any]],
    query: str,
    ll: str,
    hl: str,
    gl: str
) -> List[Dict[str, Any]]:
    collected_at = datetime.now(timezone.utc).isoformat()

    for row in rows:
        row["query"] = query
        row["ll"] = ll
        row["hl"] = hl
        row["gl"] = gl
        row["collected_at"] = collected_at

    return rows


def main() -> None:
    query = "coffee shops"
    ll = "@40.7455096,-74.0083012,14z"
    hl = "en"
    gl = "us"

    raw_data = fetch_google_maps(
        query=query,
        ll=ll,
        hl=hl,
        gl=gl
    )

    rows = parse_maps_results(raw_data)
    rows = add_search_context(rows, query=query, ll=ll, hl=hl, gl=gl)

    pd.DataFrame(rows).to_csv("google_maps_results.csv", index=False)

    with open("raw_google_maps_response.json", "w", encoding="utf-8") as file:
        json.dump(raw_data, file, ensure_ascii=False, indent=2)

    print(f"Saved {len(rows)} rows to google_maps_results.csv")
    print("Saved raw_google_maps_response.json")


if __name__ == "__main__":
    main()

What fields should you store?

For most Google Maps scraping workflows, start with this schema:

{
  "query": "coffee shops",
  "ll": "@40.7455096,-74.0083012,14z",
  "hl": "en",
  "gl": "us",
  "collected_at": "2026-06-30T09:00:00Z",
  "business": {
    "position": 1,
    "title": "Example Coffee",
    "place_id": "ChIJExample",
    "data_cid": "123456789",
    "category": "Coffee shop",
    "rating": 4.6,
    "review_count": 1280,
    "address": "123 Example St, New York, NY",
    "phone": "+1 212-000-0000",
    "website": "https://example.com",
    "maps_url": "https://...",
    "latitude": 40.7455,
    "longitude": -74.0083,
    "open_state": "Open",
    "price_level": "$$"
  }
}

For advanced workflows, add:

Field

Use case

thumbnail

UI display

hours

Business availability

service_options

Restaurant or service filters

popular_times

Demand pattern analysis

reviews_summary

Reputation intelligence

owner_response

Review management

booking_link

Conversion tracking

menu_link

Restaurant intelligence

category_ids

Classification

raw_response

Debugging and reprocessing

Common mistakes

Mistake 1: Searching without coordinates

For Maps, location is not a decoration. Use ll when you need local precision.

Mistake 2: Comparing results from different zoom levels

A query at 14z may produce different results than the same query at 16z. Store the full ll value.

Mistake 3: Treating rating alone as quality

A 4.8 rating with 12 reviews is not the same as a 4.6 rating with 2,000 reviews. Track both rating and review count.

Mistake 4: Ignoring business identity

Names can vary. Use place_id or data_cid when possible for deduplication.

Mistake 5: Not saving raw JSON

During development, always store the raw response. It makes parser changes much easier.

Mistake 6: Forgetting timestamps

Maps data changes. A snapshot without time is a fossil with no museum label.

Final thoughts

Scraping Google Maps search results with TalorData is mainly about turning local search into structured data.

Start with a query, coordinate, language, country, and Google Maps search type. Then parse business name, position, rating, reviews, category, address, phone, website, place ID, coordinates, opening status, and Maps URL.

Once the data is structured, you can use it for local SEO, lead generation, competitor monitoring, market research, franchise tracking, and AI agents.

Google Maps is a living local marketplace. A good API workflow turns that marketplace into rows your systems can reason over.

FAQ

Can I scrape Google Maps search results with TalorData?

Yes. Use the google_maps engine with a local query and location context such as ll, then parse the returned business results into JSON, CSV, or your database.

What is the most important Google Maps parameter?

For local search precision, ll is one of the most important parameters because it defines the map coordinate and zoom context.

Should I use search mode or place mode?

Use search mode when you need a list of businesses for a query. Use place mode when you already have a place_id or data_cid and want details for one specific place.

What fields should I extract first?

Start with position, business name, category, rating, review count, address, phone, website, place ID, latitude, longitude, and Google Maps URL.

立即開展您的數據業務

加入全球最強大的代理網絡

免費試用