bigywater.tech
Scrapy · 31

CrawlSpider 的 Rule:follow 与 callback 的组合

CrawlSpider 的规则到底怎么工作?callback 和 follow 的默认值有什么联系?多条规则命中同一个链接听谁的?为什么有些链接没被抓?这篇在一个小站点上把每条规则语义跑出来。

11 vs 4
同一条规则 allow="/list/|/item/",无 callback 与有 callback 抓取的请求数
第一条
多条规则命中同一链接时处理它的规则
HtmlResponse
CrawlSpider 只对这个类型的响应应用规则

follow 的默认值

实测 · 本机执行输出
  Rule(LinkExtractor(allow="/list/|/item/"))(无 callback):服务器收到 11 个请求;回调 0 次;抓到的路径 ['/', '/item/1', '/item/10', '/item/11', '/item/20', '/item/21', '/item/30', '/item/31', '/list/1', '/list/2', '/list/3']
  Rule(LinkExtractor(allow="/list/|/item/"), callback="item"):服务器收到 4 个请求;回调 3 次;抓到的路径 ['/', '/item/1', '/list/1', '/list/2']
  同上,再加 follow=True:服务器收到 11 个请求;回调 10 次;抓到的路径 ['/', '/item/1', '/item/10', '/item/11', '/item/20', '/item/21', '/item/30', '/item/31', '/list/1', '/list/2', '/list/3']

follow 没写时等于“有没有 callback 取反”:有 callback 默认不继续跟,没有 callback 默认继续跟;需要两样都做就显式写 follow=True。

规则顺序

实测 · 本机执行输出
  规则 1: /item/1 → other;规则 2: /item/ → item
    /item/1   → other
    /item/10  → other
    /item/11  → other
    /item/20  → item
    /item/21  → item
    /item/30  → item
    /item/31  → item
  调换规则 1、2 的顺序后,全部归 item:['item']

每个响应上规则按顺序依次提取链接,前面规则提取过的链接后面的规则不会再提取,所以更具体的规则要放在前面。

请求上的信息

实测 · 本机执行输出
  回调 /item/1:meta rule=1, link_text='/item/1', cb_kwargs={'tag': 'from-rule'}

规则产生的请求带 meta["rule"]、meta["link_text"],回调还能收到规则里写的 cb_kwargs。

过滤与改写

实测 · 本机执行输出
  规则:/list/ 跟踪;/item/ 回调 + process_links 丢掉以 1 结尾的 + process_request 丢掉 /item/10 并给其余请求加 meta seen_from
  服务器收到的 /item 请求:['/item/20', '/item/30'];回调 [('/20', 'list/2'), ('/30', 'list/3')]

process_links 过滤 Link 列表,process_request 改写请求或返回 None 丢弃它。

起始页与 parse

实测 · 本机执行输出
  起始页响应:[{'who': 'parse_start_url', 'url': '/', 't': 141.1}];/about 回调 ['/about']
  CrawlSpider 子类里定义了自己的 parse 以后:回调事件 ['other'](没有 my parse);服务器收到 ['/', '/about'](规则照常触发,自己的 parse 没有被调用)

起始页走 parse_start_url 加规则;自己定义 parse 在 2.19 里不会影响规则。

响应类型

实测 · 本机执行输出
  / 页面有一个指向 /feed.xml 的链接,/feed.xml 里有 <a href="/hidden">:服务器收到 ['/', '/about', '/feed.xml', '/item/1', '/list/1', '/list/2'](没有 /hidden)

只有 HtmlResponse 会被提取链接,XML、JSON 等响应不会。

分步演示

CrawlSpider 规则
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Scrapy 2.19.0 / Twisted 26.4.0 / lxml 6.1.3 / parsel 1.12.1(临时虚拟环境);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、重定向、压缩、断连等行为,并记录收到的原始请求;每个实验在临时目录里新建 Scrapy 项目或单文件 spider,命令输出来自真实的 scrapy 进程;计时用 time.perf_counter,数字每次运行会有小幅抖动。站点:/ 链接到 /list/1、/list/2、/item/1、/about、/feed.xml;/list/N 链接到 /item/N0、/item/N1 和下一页(到 3);并发 1;规则用的都是默认的 LinkExtractor 配 allow 正则
    • 没有验证:Rule 的 errback;process_request 返回新 Request 时 callback 是否被覆盖(规则的 callback 在 Request 上,返回 None 以外的请求不会重新套规则);深度(DEPTH_LIMIT)与规则的组合;大量规则时的耗时;非 UTF-8 页面上的链接提取;CRAWLSPIDER_FOLLOW_LINKS 设置(源码里已弃用并会警告,没有实测);rules 里 callback 写字符串与可调用对象的区别(只测了字符串)
    京ICP备2026067502号-1京公网安备11010502063487号