Scrapy 不是一个简单的 HTML 解析库,而是完整的爬虫框架。它负责请求调度、下载、解析、数据管道和中间件扩展。
核心组件
Scrapy Engine 负责协调各组件。
Scheduler 接收 Request,排序入队,并在引擎需要时交还请求。
Downloader 负责发送请求并返回 Response。
Spider 负责解析 Response,提取 Item 和新的 URL。
Item Pipeline 负责清洗、过滤、保存数据。
Middleware 可以拦截请求和响应,适合加代理、User-Agent、Cookie 或接入浏览器渲染。
运行流程
- Spider 给出初始 URL。
- Engine 把 Request 交给 Scheduler。
- Scheduler 排队。
- Engine 从 Scheduler 取 Request。
- Downloader 下载页面。
- Response 交给 Spider。
- Spider 提取 Item 和新 Request。
- Item 进入 Pipeline,新 Request 回到 Scheduler。
- 队列为空时爬虫结束。
Selector
Scrapy 使用 Selector 解析 HTML/XML。
def parse(self, response):
title = response.xpath("//title/text()").get()XPath 常用写法:
//tag
//div[@class="content"]
//a/@href
//h1/text()
//ul/li[position()=1]CSS 选择器:
title = response.css("title::text").get()
links = response.css("a::attr(href)").getall()get 与 getall
.get() 获取第一个匹配结果。
title = response.xpath("//title/text()").get().getall() 获取全部结果。
tags = response.css("a.tag::text").getall()分页
def parse(self, response):
for quote in response.css("div.quote"):
yield {
"text": quote.css("span.text::text").get(),
"author": quote.css("small.author::text").get(),
}
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, self.parse)工具选择
优先级一般是:
- 静态 HTML:Scrapy XPath/CSS
- 页面内 JSON:直接解析 JSON
- 轻微 JS:scrapy-playwright
- 强交互页面:Selenium
- HTML 结构很脏:BeautifulSoup 辅助清洗
Scrapy 的价值在于框架化、可扩展和适合大规模抓取。
延伸理解
复习这篇时,不要只记住名词,要把重点放在 Scrapy Engine、Scheduler、Downloader、Spider、Item Pipeline、Selector 和分页。这类知识如果只停留在定义层面,很容易在面试或项目中答得很散。更好的理解方式是把它放进一个具体场景:谁在调用它,输入从哪里来,失败后谁负责恢复,数据或状态会不会被重复处理。
- 爬虫工程的难点通常不是发请求,而是页面变化、等待策略、去重、限速、异常恢复和数据质量。
- 选择 BeautifulSoup、Selenium 或 Scrapy 时,要先判断页面是否动态、数据规模和后续清洗需求。
- 可靠爬虫需要日志、断点续跑、失败重试和字段级校验,不能只依赖一次成功运行。
在真实项目中,可以把它当成一个判断框架:先确认输入、约束、失败场景和可观测性,再决定具体工具或写法。 如果一个方案看起来很简单,要继续追问它在规模扩大、权限变化、异常恢复和团队协作下是否仍然成立。
实践检查清单
- 明确这个知识点在系统中的位置:是开发时约束、运行时能力、基础设施能力,还是协作流程。
- 写出一个最小可运行例子,并补一个失败例子;只会写 happy path 说明理解还不够稳。
- 记录常见误用:例如边界条件、权限假设、性能假设、同步/异步差异或环境差异。
- 把概念和项目经历关联起来:如果面试被追问,可以用自己的项目说明为什么这样选。
- 最后用一句话总结取舍:它牺牲了什么,换来了什么。
自测问题
- 这个主题解决的核心问题是什么?
- 如果不用当前方案,还有哪些替代方案?代价是什么?
- 最容易出错的边界条件在哪里?
- 如何在代码、测试或监控中验证它真的可靠?
项目化应用场景
可以把这类知识放到一个招聘信息或商品信息采集系统里理解:先判断页面是静态 HTML 还是动态渲染,再选择 BeautifulSoup、Selenium 或 Scrapy;采集后要做字段清洗、去重、失败重试和持久化。稳定爬虫的关键不是一次能抓到数据,而是页面结构变化、网络超时、反爬限制和部分字段缺失时仍然能恢复。
常见误区:
- 直接写死脆弱 selector,没有 fallback。
- 没有限速和重试,容易被封或丢数据。
- 只保存原始数据,不做字段级质量检查。