在过去一年里,一个越来越常见的声音开始出现在数据圈:
“解析规则这一步,其实可以交给大模型。”
理由听起来很诱人:
HTML 结构复杂、页面频繁改版、人工维护 XPath 成本高,而大模型“看一眼页面就能写规则”。
但工程经验告诉我们一句老话:
凡是感觉“省事”的地方,往往藏着系统性风险。
这篇文章不讨论立场,只做一件事:
用一组可复现的 A/B 实验,对比「人工解析规则」和「大模型生成解析规则」在真实爬虫场景中的表现。
一、实验问题定义
我们要回答的不是“能不能用”,而是三个更工程化的问题:
- 在真实页面环境下,大模型生成的解析规则成功率如何?
- 当页面出现轻微结构变化时,哪一方更稳定?
- 在代理 IP、多地区页面差异下,规则是否会发生漂移?
二、实验场景说明
业务背景
假设我们在做一个内容聚合服务,需要采集资讯类网页的三个字段:
- 标题
- 正文
- 发布时间
页面特点如下:
- 页面由服务端渲染
- 存在广告、推荐模块
- 不同地区访问返回的 HTML 存在细微差异
这是一个非常典型、但并不极端的爬虫场景。
三、A/B 两组方案定义
A 组:人工编写解析规则
特点:
- 由工程师手动分析 DOM
- 使用稳定层级 XPath
- 明确字段边界
- 可解释、可调试
B 组:大模型生成解析规则
流程:
- 抓取完整 HTML
- 将 HTML 片段 + 字段描述交给大模型
- 由大模型输出 XPath / CSS Selector
- 程序直接使用该规则解析
这是目前很多“AI + 爬虫”方案真实采用的模式。
四、实验环境与代理配置
为了避免“本地页面过于干净”的问题,实验中所有请求都通过代理 IP 发起,确保:
- 页面为真实线上版本
- 触发地区差异
- 包含更多不确定性因素
下面是统一使用的请求代码示例。
import requests
proxies = {
"http": "http://用户名:密码@:proxy.16yun.cn:3100",
"https": "http://用户名:密码@proxy.16yun.cn:3100"
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
}
def fetch_html(url):
response = requests.get(
url,
headers=headers,
proxies=proxies,
timeout=10
)
response.raise_for_status()
return response.text
说明:
- 代理IP使用亿牛云爬虫代理
- 用户名、密码、域名、端口需替换为实际配置
- 每次请求随机更换 IP,模拟真实访问
五、解析实现对比
A 组:人工解析代码
from lxml import etree
def parse_by_human(html):
tree = etree.HTML(html)
title = tree.xpath("//h1[@class='article-title']/text()")
content = tree.xpath("//div[@class='article-content']//p/text()")
publish_time = tree.xpath("//span[@class='publish-time']/text()")
return {
"title": title[0] if title else None,
"content": "\n".join(content).strip(),
"publish_time": publish_time[0] if publish_time else None
}
特点非常明显:
- XPath 较长
- 明确避开广告区域
- 每一步都可人工验证
B 组:大模型生成解析规则(示意)
假设大模型返回的结果如下:
{
"title": "//h1/text()",
"content": "//div[contains(@class,'content')]//text()",
"publish_time": "//time/text()"
}
解析代码如下:
def parse_by_llm(html, rules):
tree = etree.HTML(html)
def extract(rule):
result = tree.xpath(rule)
return result[0].strip() if result else None
return {
"title": extract(rules["title"]),
"content": extract(rules["content"]),
"publish_time": extract(rules["publish_time"])
}
从代码角度看,B 组非常“优雅”。
六、实验结果统计
我们对同一批 URL 进行 200 次请求,统计结果如下(文字描述):
- 首次成功率
- A 组:约 97%
- B 组:约 92%
- 页面结构轻微调整后
- A 组:成功率下降到约 90%
- B 组:成功率下降到约 65%
- 多地区代理访问
- A 组:字段偶发为空,但结构稳定
- B 组:正文字段明显掺杂推荐内容、版权信息
七、问题出在哪里
通过失败样本回放,我们发现几个非常关键的现象。
1. 大模型倾向于“语义正确,而非结构正确”
它更容易选择:
- 最短 XPath
- 最宽泛的 class 匹配
- 表面看起来“像正文”的区域
但工程上,最像正文的区域,往往不是最稳定的区域。
2. 代理IP放大了规则不稳定性
不同 IP 访问返回的 HTML 中:
- 广告模块顺序不同
- 推荐内容位置变化
- A/B 测试标签不同
人工规则通常会主动规避这些区域,而大模型并不知道哪些是“危险区域”。
3. 错误往往是“静默的”
B 组最危险的一点不是报错,而是:
- 能解析
- 有内容
- 但内容是错的
这类错误如果没有人工抽检,很可能直接进入数据仓库。
八、实验结论
通过这次 A/B 对抗实验,我们得到一个非常清晰的工程结论:
- 大模型适合做“解析规则的候选生成器”
- 不适合直接成为“生产解析规则的唯一来源”
- 关键字段的解析,必须是确定性、可解释的
一句话总结:
大模型可以帮你“想规则”,但不能替你“承担规则失效的后果”。
九、一个更稳妥的落地建议
在真实项目中,更推荐的组合方式是:
- 大模型负责:
- 新站点初始规则生成
- 页面结构分析建议
- 人工负责:
- 规则确认
- 关键字段兜底
- 系统负责:
- 失败率监控
- 代理 IP 场景回放
这不是反对 AI,而是让 AI 放在它最擅长的位置。