AI 网页采集器生成器
给一个网址 + 几个目标字段,系统自动推断抓取规则,并生成一个独立可运行的采集脚本。
一分钟上手
# 1) 自检(离线,不联网)
python m06_smoke_test.py # 期望输出 SMOKE OK,退出码 0
# 2) 抓页面 + 推断规则 + 生成脚本 + 立刻出数据
python m05_cli.py collect --url "https://example.com/list" --fields "标题,价格,时间"
# 3) 只想看规则
python m05_cli.py infer --html-file page.html --fields "标题,价格,时间"
生成的脚本可以脱离本项目单独运行(纯标准库):
python _out/collector_xxxxxxxx.py --url "https://example.com/list" --out records.csv
python _out/collector_xxxxxxxx.py --html-file page.html --out records.json --format json
模块契约(谁给谁什么)
| 模块 | 文件 | 对外契约 |
|---|---|---|
| 1 抓取与缓存 | m01_fetcher.py | fetch_url(url, use_cache=True, seed_html=None) -> {'ok','status','html','cached','error'};cache_clear(url=None)、stats() |
| 2 DOM 与字段定位 | m02_dom_parse.py | parse_html(html) -> Node;Node.iter/find_all(tag,cls,id)/text_content;css_of(node) -> str;find_fields(root, fields) -> {field: [{'node','selector','score','sample'}]} |
| 3 规则推断 | m03_rule_infer.py | infer_rules(html_or_root, fields) -> {'fields','missing','url_selector','RULES'};clean_value(text, field);apply_rules(root, rules) |
| 4 采集脚本生成 | m04_codegen.py | generate_script(rules, url) -> (src, filename, sha);save_script(rules, outdir, url);TEMPLATE |
| 5 命令行入口 | m05_cli.py | main(argv),子命令 fetch / infer / gen / collect / doctor |
| 6 集成冒烟与说明 | m06_smoke_test.py、本文件 | python m06_smoke_test.py 无参 exit 0 |
跨模块 import 规则:一律用完整文件名(import m01_fetcher),不使用包内相对导入;每个模块都要能单独 python mNN_xxx.py 跑通自带自测。
设计取舍(踩过的坑,别改回去)
- 字段值必须落在叶子上。 容器节点(
div.list/div.item)文本更长、选择器更短,纯靠加分永远压不住叶子,结果抽出来的是一整段而不是那个值。所以候选排序的第一关键字是「是不是叶子」,第二关键字才是分数。 <a>标签不等于链接。 标题常挂在<a>上,机械地按标签抓href会把/item/1001当成标题。只有字段名本身是链接语义时才抓href。- 缺字段要报出来。 推断不到就把字段放进
missing并让 CLI 返回非 0,绝不拿兜底候选(score<=1)去跑生产。 - 生成脚本自带解析器。 生成物要能拷到别的机器上直接跑,所以把微型 HTML 解析器和选择器执行器内联进去,不 import 本项目模块。
- 文件名带规则 sha。 同一份规则永远生成同一个文件名,改规则换 sha,版本对账不用猜。
- 全链路必须能离线跑。 所有自测都用内置示例 HTML,不依赖网络;抓取失败路径也要有断言(
ok=False且带error)。
目录
m01_fetcher.py 抓取(UA/超时/重试/本地缓存/seed 注入)
m02_dom_parse.py 容错解析 + 选择器回溯 + 字段候选打分
m03_rule_infer.py 规则推断 + 字段值清洗
m04_codegen.py 生成独立采集脚本
m05_cli.py 命令行(fetch/infer/gen/collect/doctor)
m06_smoke_test.py 集成冒烟(9 项断言)
README.md 本文件
已知边界
- 单页面采集,不做站内翻页爬取(需要时在生成脚本外面套循环)。
- 选择器执行器只支持本项目自己生成的格式(
tag.class:nth-of-type(n) > ...),不是通用 CSS 引擎。 - 依赖
div.item:nth-of-type(k)的规则对同结构列表稳定,但页面改版后必须重新推断。