kp-009
结构化数据抽取:JSON 接口与数据定位
前置知识
本文基于模型知识整理,建议核对官方文档(见 参考资料)。
一句话定义
现代站点的数据大多由前端调用 JSON 接口渲染;绕过 HTML、直接定位并请求这些接口,是效率与稳定性都最高的抽取路线。
为什么重要
接口返回的是已结构化的 JSON:没有解析器兼容问题、字段语义清晰、天然支持分页参数。接口路线优先于 HTML 路线是资深爬虫工程师的第一条经验法则;做不到接口直连时才退回渲染方案。
前置知识
kp-002(报文与 Content-Type)、kp-006(Session)。
核心概念
- XHR / Fetch 请求:前端发起的异步数据请求,可在 DevTools Network 面板的 Fetch/XHR 过滤下看到。
- 响应 envelope:接口常见包裹结构
{code, msg, data},真实数据在data内。 - 参数发现:Query String、请求体、请求头里的时间戳/签名/token。
- 防御式取值:
data.get("list", [])链式默认值,字段缺失不崩。
原理与机制
接口发现的操作序列(以 DevTools 为工作台):
1. Network 面板 → 过滤 Fetch/XHR → 刷新页面 → 按大小排序
2. 找到响应含目标文本的那条请求(搜 Preview 内容)
3. 记录: URL / Method / Query / Body / 关键请求头(Cookie·Referer·token)
4. 用 requests 复刻该请求 → 比对响应是否一致
5. 改变翻页参数 → 观察响应变化 → 归纳翻页规则(交 kp-010)
防御式解析模板:
import requests
r = requests.get("https://api.example.com/v1/list",
params={"page": 1, "size": 20},
headers={"User-Agent": UA, "Referer": "https://example.com/"},
timeout=(5, 20))
payload = r.json()
items = payload.get("data", {}).get("list") or [] # 双重缺省 + or 防御 None
for it in items:
yield {
"id": it.get("itemId"),
"title": (it.get("title") or "").strip(),
"price": it.get("price", {}).get("current"),
}
实例或案例
对比同一数据源的两种路线:HTML 路线需要 BS4 + 选择器 + 编码处理,改版即断;JSON 接口路线只需复刻一个 GET,字段名即业务语义(skuName/price)。接口路线的额外风险是参数校验更严(签名、频控),这把战场交给了 kp-015 与 kp-016。
常见误区
- 误区一:拿到 JSON 当 HTML 用 BS4 解析。
resp.json()一步到位,优先级永远高于解析 HTML。 - 误区二:假设字段必然存在。 接口对不同状态的实体返回的字段集不同;一律
get加默认值。 - 误区三:接口有签名就放弃。 先看签名是否只是时间戳+固定盐(kp-015 的入门场景);实在不可还原再退回渲染路线。
自测题
- 为什么说接口路线优先于 HTML 路线?
答:结构化、字段语义明确、无解析兼容问题、支持参数化翻页;维护成本显著更低。
- 在 DevTools 里按什么顺序定位数据接口?
答:过滤 Fetch/XHR → 刷新 → 按大小/名称排查 → Preview 搜索目标文本 → 记录完整请求要素。
payload.get("data", {}).get("list") or []防住了哪两类崩溃?
答:data 键不存在导致的 AttributeError;list 为 None 时后续 for 循环的 TypeError。
与其他知识点的关系
kp-014 是本篇的观察手段;kp-010 在接口参数上做翻页;kp-015 处理带加密参数的接口。
延伸阅读
MDN「Fetch API」概念篇;Chrome DevTools 文档「Inspect network activity」。