如何使用 TalorData 抓取 Google 地图搜索结果
了解如何使用 TalorData SERP API 抓取 Google 地图搜索结果。本技术指南涵盖了地图参数、Python requests 库的使用、本地商家信息字段(包括评分、评论、地址、电话号码、网站、地点 ID 和坐标)、CSV 导出以及本地 SEO 工作流程。
Google Maps results 是典型的 local-intent data。它能告诉你某个查询下哪些商家出现、排名如何、评价强不强、联系方式是否完整,以及商家在本地市场中的可见度。
如果你在做 local SEO tools、lead generation workflows、market research dashboards、competitor monitors 或 AI agents,Google Maps data 可以回答这些问题:
|
问题 |
为什么重要 |
|
“dentist near me” 会出现哪些商家? |
Local visibility |
|
指定坐标附近,哪个竞品排名更高? |
Local SEO tracking |
|
哪些商家 rating 和 review count 更强? |
Reputation analysis |
|
哪些 listing 有 phone 和 website? |
Lead enrichment |
|
哪些区域竞争更密集? |
Market research |
|
哪些 listing 在多个城市都出现? |
Expansion planning |
|
AI agent 应该推荐哪些本地商家? |
AI workflow context |
这篇指南会建立一个 Python workflow:把 Google Maps query 发送到 TalorData,获取 structured JSON,提取本地商家字段,最后导出 CSV。
整体流程:
Search query + map location
↓
TalorData SERP API
↓
Google Maps results in JSON
↓
Parse business fields
↓
Normalize place data
↓
Export to CSV or database
什么是抓取 Google Maps search results?
这里的 “scraping Google Maps”,指的是通过 TalorData SERP API 采集结构化 Google Maps-style search results。
它不是控制浏览器、手动滚动页面,或从 Google Maps 界面抓 HTML。
我们要采集的是这些字段:
|
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 response 可用于 local business search workflows,并可在可用时返回 business name、place ID、address、coordinates、category、rating、review count、rank position、opening status、phone number、website、Google Maps URL、thumbnail 和 price level 等字段。
什么时候适合使用 Google Maps SERP API?
当你的问题和 local visibility 有关,就适合使用 Google Maps search results。
|
Use case |
Example |
|
Local SEO rank tracking |
在不同坐标追踪 “plumber near me” |
|
Lead generation |
采集带 phone 和 website 的本地商家 |
|
Competitor research |
比较 rating、reviews 和 positions |
|
Market analysis |
按城市统计某品类商家 |
|
Franchise monitoring |
监控品牌在多市场的可见度 |
|
Review intelligence |
追踪 rating 和 review count |
|
AI agents |
把本地商家选项喂给推荐流程 |
Google Maps rankings 对 location 很敏感。同一个 query,在不同坐标附近可能返回不同商家。所以 location control 很重要。
核心 Google Maps 参数
先从这些参数开始。
|
Parameter |
Required |
Purpose |
Example |
|
|
Yes |
选择 Google Maps search |
|
|
|
Search queries |
商家、品类或 local intent query |
|
|
|
建议使用 |
Latitude、longitude 和 zoom |
|
|
|
Optional |
Search mode |
|
|
|
Place lookup |
Google Maps place reference |
|
|
|
Place lookup |
Google CID-style place reference |
|
|
|
Optional |
Google domain |
|
|
|
Optional |
界面语言 |
|
|
|
Optional |
国家上下文 |
|
|
|
Optional |
Freshness control |
|
Google Maps requests 中,ll 使用 @latitude,longitude,scale 这类坐标格式,Maps search type 支持 search-style 和 place-style workflow。
Search mode vs place mode
通常有两种使用方式。
Search mode
当你需要一组商家列表时,用 search mode。
示例:
coffee shops near Manhattan
dentists in Austin
hotels near JFK Airport
plumbers in Chicago
restaurants near Times Square
Search request 需要 query 和 location context。
{
"engine": "google_maps",
"type": "search",
"q": "coffee shops",
"ll": "@40.7455096,-74.0083012,14z",
"hl": "en",
"gl": "us"
}
Place mode
当你想查某个已知商家的详细数据时,用 place mode。
你可以使用之前 search result 中的 place_id 或 data_cid。
{
"engine": "google_maps",
"type": "place",
"place_id": "ChIJExamplePlaceId",
"hl": "en",
"gl": "us"
}
常见流程:
Search query
↓
Get local business results
↓
Extract place_id or data_cid
↓
Request place details
↓
Store richer business data
Step 1:设置 API key
将 TalorData API key 和 endpoint 存成环境变量。查看设置指南>>
export TALORDATA_API_KEY="your_api_key_here"
export TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"
Windows PowerShell:
setx TALORDATA_API_KEY "your_api_key_here"
setx TALORDATA_SERP_ENDPOINT "your_talordata_serp_endpoint_here"
安装 Python dependencies:
pip install requests pandas
Step 2:建立可复用 Python client
这个 function 会发送 Google Maps search request 并返回 JSON。
如果你的 TalorData account 使用不同 request style,请调整 endpoint 或 authentication format。
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()
执行基本搜索:
if __name__ == "__main__":
data = fetch_google_maps(
query="coffee shops",
ll="@40.7455096,-74.0083012,14z",
hl="en",
gl="us"
)
print(data)
Step 3:检查 raw response
写 parser 前,先检查 JSON。
import json
print(json.dumps(data, indent=2, ensure_ascii=False)[:5000])
可以找这类 result arrays:
local_results
maps_results
place_results
results
organic_results
实际 top-level field 可能会因 response type 而变。不要太早把 parser 刻在石头上。先看洞穴墙,再拿凿子。
Step 4:解析 Google Maps results
下面是一个保守 parser,会检查几个可能的结果容器,并提取常见本地商家字段。
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
使用:
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:保存成 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())
CSV 可能长这样:
|
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:加入 search context
没有 context 的 Maps result,很难在之后比较。
每一列都应该保存 query、coordinate、language、country 和 timestamp。
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
使用:
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)
接着就能比较变化:
|
Change |
Meaning |
|
Position changed |
本地排名变化 |
|
Rating changed |
口碑变化 |
|
Review count increased |
更多顾客反馈 |
|
Business disappeared |
排名或可见度变化 |
|
New competitor appeared |
市场变化 |
|
Website added or removed |
Listing completeness 变化 |
Step 7:搜索多个坐标
对 local SEO 来说,只查一个 city-level location 通常太粗。
更好的方式,是对同一个 query 跑 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)
这可以帮你发现:
|
Signal |
Example |
|
Local rank variation |
某咖啡店在一个坐标 #1,在另一个坐标 #8 |
|
Competitor clusters |
某区域竞品密集 |
|
Visibility gaps |
商家离开小半径后就消失 |
|
Review advantage |
评论更强的竞品更常出现 |
|
Expansion areas |
某些区域强 listing 较少 |
Step 8:获取 place-level details
Search result 给你一组列表。Place lookup 可以让你深入看一个商家。
使用 search result 中的 place_id 或 data_cid。
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()
示例:
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])
当你想在搜索后补充特定商家详情时,用 place mode。
Step 9:完整 script
下面是一个完整示例:搜索 Google Maps、解析本地商家字段、加入 context,最后导出 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()
应该保存哪些字段?
大多数 Google Maps scraping workflows 可以先用这个 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": "$$"
}
}
进阶 workflow 可以加:
|
Field |
Use case |
|
|
UI display |
|
|
Business availability |
|
|
餐厅或服务筛选 |
|
|
需求模式分析 |
|
|
Reputation intelligence |
|
|
Review management |
|
|
Conversion tracking |
|
|
Restaurant intelligence |
|
|
Classification |
|
|
Debug 和 reprocessing |
常见错误
没有使用坐标搜索
对 Maps 来说,location 不是装饰。需要 local precision 时,请使用 ll。
比较不同 zoom level 的结果
14z 和 16z 可能返回不同结果。保存完整 ll value。
只看 rating
4.8 分但只有 12 条评论,和 4.6 分但有 2,000 条评论,不是一回事。Rating 和 review count 要一起看。
忽略 business identity
商家名称可能会变。去重时优先使用 place_id 或 data_cid。
不保存 raw JSON
开发阶段一定要保存 raw response。后续调整 parser 会更容易。
忘记 timestamps
Maps data 会变。没有 timestamp 的 snapshot,就像没有标签的化石。
结语
使用 TalorData 抓取 Google Maps search results,本质上是把 local search 变成 structured data。
先从 query、coordinate、language、country 和 Google Maps search type 开始。然后解析 business name、position、rating、reviews、category、address、phone、website、place ID、coordinates、opening status 和 Maps URL。
数据结构化后,就可以用于 local SEO、lead generation、competitor monitoring、market research、franchise tracking 和 AI agents。
Google Maps 是一个活着的本地市场。好的 API workflow,会把这个市场整理成系统能理解的数据列。