Scrapy 进阶实战:CrawlSpider 架构与规则引擎解析
CrawlSpider 工作机理
CrawlSpider 继承了基础的 Spider 类,专为自动化多页爬取场景设计。其核心能力在于自动处理网页间的关联跳转:从初始 URL 列表开始抓取内容,利用预定义的规则识别并提取后续页面的链接,进而发起新的请求,形成闭环的爬取路径。
sequenceDiagram
participant Scheduler as 调度器
participant Downloader as 下载器
participant Parser as 规则引擎
participant Target as 目标数据
start_urls -.->Scheduler
Scheduler -->>Downloader: 发起请求
Downloader -->>Parser: 返回响应文本
Parser -->>Target: 提取有效信息
Parser -->>Scheduler: 提交新 URL
上述序列图展示了请求在调度、下载及规则处理之间的流转过程。
模板生成
通过以下命令行指令可快速初始化基于 CrawlSpider 的项目结构:
scrapy genspider -t crawl 项目名称 域名范围
规则对象 (Rule Object)
规则定义位于 scrapy.spiders 模块下(注:旧版本为 scrapy.contrib)。每个 Rule 实例控制特定响应内容的解析逻辑。
from scrapy.spiders import Rule
Rule(
link_extractor=LinkExtractor(...),
callback=None,
cb_kwargs=None,
follow=True,
process_links=None,
process_request=None
)
各参数具体含义如下:
- link_extractor: 负责指定如何从页面中提取链接对象(通常配合
LinkExtractor使用)。 - callback: 当匹配到链接后触发的回调函数名。此处需注意:
必须避免使用名为parse的函数作为回调。因为CrawlSpider基类依赖parse方法处理默认流程,若用户手动覆盖会导致爬虫逻辑冲突或失效。 - follow: 布尔值。若设为 True,则对提取到的链接继续执行后续规则;默认为 True。
- process_links: 用于接收并过滤提取到的原始链接集合。
- process_request: 用于拦截并修改生成的 Request 对象。
链接提取器 (LinkExtractor)
这是实现定向抓取的核心组件,主要用于分析 Response 中的超链接。
核心方法
所有提取器共享 extract_links(response) 公共接口,输入 Response 对象,输出包含 scrapy.link.Link 对象的列表。
配置参数详解
from scrapy.linkextractors import LinkExtractor
LinkExtractor(
allow=(), # 正则白名单
deny=(), # 正则黑名单
allow_domains=(), # 允许抓取的域名
deny_domains=(), # 禁止抓取的域名
restrict_xpaths=(),# XPath 定位过滤
tags=('a','area'), # 标签类型
attrs=('href'), # 属性名称
canonicalize=True, # 是否统一 URL 格式
unique=True, # 是否去重
process_value=None # 自定义值处理
)
- allow/deny: 支持传入正则表达式元组进行 URL 白名单或黑名单过滤。留空表示全部匹配或不加限制。
- allow_domains: 限制仅提取指定域名的绝对路径链接。
- restrict_xpaths: 结合 XPath 表达式限定搜索范围,仅在该节点内查找符合要求的链接。
交互式验证
可在 Shell 环境中即时测试提取效果:
- 启动 Shell 模式:
scrapy shell "https://www.example-domain.com/page" - 导入模块:
from scrapy.linkextractors import LinkExtractor - 创建实例并筛选:
lex = LinkExtractor(restrict_xpaths="//div[@class='pagination']/a") - 执行提取:
links = lex.extract_links(response)
完整爬虫示例
将提取器集成至 CrawlSpider 中,并处理具体的业务数据字段:
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from myproject.items import BookContentItem
class ChapterListSpider(CrawlSpider):
name = "book_list_crawler"
allowed_domains = ["target-site.com"]
start_urls = [
"http://www.target-site.com/series/1/read/101"
]
rules = [
Rule(
LinkExtractor(
restrict_xpaths='//div[@class="reader-nav"]/a[last()]'
),
callback='parse_book_content',
follow=False
)
]
def parse_book_content(self, response):
# 提取正文内容
raw_text = response.xpath("//div[@id='main-content']/text()").getall()
# 组装 Item
item_data = BookContentItem()
item_data['full_text'] = "".join(raw_text)
yield item_data
在此代码结构中,需注意 rules 列表里的回调写法:
1. 函数名称必须使用字符串形式引用(如 'parse_book_content')。
2. 严禁命名 parse 以避免基类冲突。
3. 确保参数顺序与 Rule 构造函数定义一致。