SerpBase 地图两阶段采集:place_id、data_id 别混,成本先算

做本地商家分析,第一反应是调 /google/maps/search。但列表里只有名称、地址、评分、坐标——要拿营业时间、照片、评论,必须再调详情和评论端点。问题是:三个端点用的是三种不同的 id,混用一个就查不到,或者查到别家。

这篇把两阶段采集的 id 映射和成本算清楚。

三个 id 从哪来、用在哪

Maps 搜索(POST /google/maps/search,2 credits/次,按 query + location.location_query 查)返回的每条 places 里有四个标识:

字段 形态 用途
place_id ChIJ... 开头的字符串 详情端点用这个(参数名是 id)
data_id 0x...:0x... 形态 评论端点用这个(参数名是 data_id)
feature_id 0x...:0x... 与 data_id 同源,做内部关联
cid 数字串 拼 Google Maps 链接

详情:POST /google/maps/detail,3 credits/次,参数 {"id": place_id}。
评论:POST /google/maps/reviews,2 credits/次,参数 {"data_id": data_id}。

最容易犯的错,是把 data_id 传给详情端点——两个都是 0x... 开头,看着一模一样,但语义不同。

两阶段采集的代码骨架

import os
import requests

HEADERS = {"Content-Type": "application/json",
           "X-API-Key": os.environ["SERP_BASE_API_KEY"]}
BASE = "https://api.serpbase.dev"


def places(query: str, location: str, page: int = 1) -> list[dict]:
    data = requests.post(f"{BASE}/google/maps/search", headers=HEADERS,
                         json={"query": query,
                               "location": {"location_query": location},
                               "page": page},
                         timeout=(5, 30)).json()
    return data.get("places", []) if data.get("status") == 0 else []


def detail(place_id: str) -> dict:
    data = requests.post(f"{BASE}/google/maps/detail", headers=HEADERS,
                         json={"id": place_id}, timeout=(5, 30)).json()
    return data.get("place", {}) if data.get("status") == 0 else {}


def reviews(data_id: str) -> list[dict]:
    data = requests.post(f"{BASE}/google/maps/reviews", headers=HEADERS,
                         json={"data_id": data_id}, timeout=(5, 30)).json()
    return data.get("reviews", []) if data.get("status") == 0 else []


for p in places("咖啡", "Seattle, WA")[:20]:      # 只对前 20 家做二次调用
    d = detail(p["place_id"])
    r = reviews(p["data_id"])
    print(p["name"], d.get("open_status"), len(r))

成本:先算,再决定拉多少

地图搜索每页返回 20 家(每页一次请求,2 credits)。三段价格:搜索 2c、详情 3c、评论 2c。

  • 全量两阶段:100 家 = 搜索 5 页(10c)+ 详情 100 次(300c)+ 评论 100 次(200c)= 510 credits
  • 分层采集:只对排名前 20 家做详情和评论 = 10 + 60 + 40 = 110 credits

两者差近五倍,而分析价值通常集中在头部商家。先搜全量,再对 Top N 做深挖,是这类采集的默认姿势。

存储:主表 + 快照表

  • places 主表以 place_id 为唯一键,存 data_id、feature_id、cid、名称、坐标
  • place_details 存详情(含 open_status、照片),按采集时间保留版本
  • place_reviews 用「快照 + 追加」:评论数会变,覆盖会让历史消失

评论是非结构化的长文本,单独存表,别塞进主表的一个 JSON 字段——后面做关键词提取、情感分析,都要逐条处理。

五个坑

坑 1:把 data_id 传给详情端点。 查不到或报参数错误,参数错误不计费,但任务失败。记住:详情用 place_id(参数 id),评论用 data_id。

坑 2:对搜索结果全量做两阶段。 510 credits 一次跑完,免费额度当场清零。先分层。

坑 3:以为评论能翻页拿全。 当前评论端点返回的是「第一页」,没有完整历史。做趋势分析时要知道这是抽样。

坑 4:把 open_status 当静态字段。 它是采集时刻的快照,「营业中」明天可能变成「已打烊」,别写成固定值。

坑 5:同名商家不去重。 连锁店同名不同址,唯一键必须用 place_id,不能用名称。

小结

地图数据的关键不是调用本身,而是id 映射和分层成本:搜索拿列表(2c)→ 记下 place_id 与 data_id → 只对 Top N 调详情(3c)和评论(2c)→ 主表用 place_id 去重。三件事做对,本地商家数据集就稳了。

三个端点的参数与字段以 SerpBase 文档 为准,产品页上有每个端点的请求示例。你们做本地数据采集时,二次调用的比例是多少?评论区聊聊。

posted @ 2026-10-25 09:21  蜘蛛人  阅读(6)  评论(0)    收藏  举报