写在前面
学爬虫时,我们会被灌输一堆名词:requests、BeautifulSoup、Scrapy、Selenium、Redis……
结果就是:学了一堆,脑子里一团乱麻。这篇文章想解决一个问题:爬虫系统为什么是现在这个样子?每一层为什么这么分?要回答这个问题,得先从"爬虫到底在干什么"说起。
一、爬虫的本质:一条数据流水线
抛开所有工具,任何爬虫做的事情,本质都是一条流水线:目标网站 → 请求 → 拿到数据 → 解析 → 保存
这条流水线看似简单,但每一环都会遇到问题:
| 环节 | 会遇到什么问题 |
|---|---|
| 请求 | 网络慢、被限速、被封 IP、需要登录 |
| 拿到数据 | 有的是 HTML,有的是 JSON,有的是 JS 动态渲染 |
| 解析 | HTML 结构乱、数据藏在标签深处、需要正则/JSON 提取 |
| 保存 | 数据量大、需要去重、需要查得快 |
每解决一类问题,就诞生一个工具。工具越来越多,就要分层归类。这就是"爬虫生态圈"的由来。
二、为什么是这 7 层
先说结论——这 7 层不是人为划定的,而是沿着"数据流动方向"自然形成的:
数据从"发请求"到"存下来",会依次经过 5 个环节:调度 → 框架 → 渲染 → 请求 → 解析 → 存储
再加上一层"反爬"——因为它不属于流水线的任何一个环节,而是横切在请求和渲染之上的。
所以 7 层是这么来的:
| 层 | 存在的原因 |
|---|---|
| 请求层 | 爬虫必须发 HTTP 请求 |
| 解析层 | 拿到的数据必须被提取 |
| 渲染层 | 有些页面的数据靠 JS 动态生成 |
| 框架层 | 一个爬虫有很多重复逻辑(调度、去重、重试) |
| 存储层 | 抓到的数据必须落地 |
| 反爬层 | 网站会主动阻止爬虫 |
| 调度层 | 大规模爬取需要多机协作和定时任务 |
每一层都不是凭空发明的,而是"因为有一类问题反复出现"才被抽象出来的。
这个布局的核心逻辑是:一条主干流水线 + 一条横切辅助线。
具体来说:
① 主干从左到右 = 数据流动方向
调度 → 框架 → 渲染 → 请求 → 解析 → 存储这对应爬虫一次完整抓取的时间顺序:先被调度器唤起,框架接管,发请求(或先渲染),拿回数据,解析,最后存储。
② 反爬/辅助层在下方,用虚线指向上方
它不在主线上,因为它不产生数据、也不消费数据,而是横切在请求和渲染之上——每次请求前加代理/加 UA,每次渲染前过指纹检测。所以画成虚线"介入"主线。③ 为什么渲染层在请求层左边
因为在真实执行中,渲染层内部会调用请求层——Playwright 发 HTTP 请求,把页面拿到浏览器里跑 JS。渲染层是"包装了请求层"的更高层。④ 为什么框架层在渲染层左边
Scrapy 作为框架,调度渲染层的调用(通过 scrapy-playwright),所以框架比渲染更靠"上游"。⑤ 调度层在最左
它最上游,决定"什么时候跑、跑几台机器",不接触任何具体数据。
三、逐层讲:为什么是这些工具
第 1 层:请求层
为什么有这一层:爬虫和网站之间的所有交互,都通过 HTTP 请求完成。这一层就是把"发请求"这件事做好的工具集。
为什么是这些工具:
| 库 | 为什么是它 |
|---|---|
| Requests | API 设计极简,几乎所有爬虫教程都从它入门;同步、易调试 |
| httpx | 保留 Requests 手感,同时支持异步和HTTP/2 |
| aiohttp | 纯异步,为高并发而生;性能比 httpx 更极致 |
| urllib3 | Requests 的底层依赖,一般不用直接碰 |
这层工具的核心矛盾是"同步 vs 异步":
同步:代码简单、易读,但同一时刻只能等一个响应
异步:能同时等几百个响应,但代码复杂度高
所以这层至少要学两个:一个同步(Requests)、一个异步(httpx 或 aiohttp)。
第 2 层:解析层
为什么有这一层:请求回来的是原始字符串(HTML 或 JSON),必须从中提取你要的数据。
为什么是这些工具:
| 库 | 为什么是它 |
|---|---|
| BeautifulSoup | 容错最强,HTML 不规整也能解析;新手友好 |
| lxml | 速度最快的 HTML 解析器;支持 XPath |
| parsel | Scrapy 内置,XPath + CSS 双语法 |
| pyquery | 语法最像 jQuery,前端背景的人上手快 |
| re | 正则,适合从文本里抠固定格式的数据 |
| jsonpath | 专抓 JSON 数据(接口返回大多是 JSON) |
这层工具的核心矛盾是"容错 vs 速度":
BeautifulSoup容错好,但慢lxml快,但对脏 HTML 不友好parsel兼顾两者,但只在 Scrapy 里用着最爽
选型逻辑:数据结构规整 →lxml/parsel;数据结构脏 →BeautifulSoup。
第 3 层:渲染层
为什么有这一层:请求层只能拿到服务器返回的原始 HTML。如果页面的数据是 JavaScript 运行后动态生成的,请求层拿到的就是"空壳 HTML"。
这一层的工具做的事:启动一个真实浏览器,执行 JS,拿到渲染后的 DOM。
为什么是这些工具:
| 工具 | 为什么是它 |
|---|---|
| Playwright | 微软出品,多浏览器支持,速度快,反检测强 |
| Selenium | 最老牌的浏览器自动化,生态最广,但慢 |
| Pyppeteer | Puppeteer 的 Python 版,主要驱动 Chrome |
| DrissionPage | 国产,融合 requests 和浏览器,效率高 |
这层工具的核心矛盾是"速度 vs 真实性":
用真实浏览器 → 慢,但能拿到完整数据
不用浏览器 → 快,但可能拿不到数据
所以这层工具只有在"请求层拿不到数据"时才用——它是补丁,不是主路。
第 4 层:框架层
为什么有这一层:爬虫做多了,你会发现每个爬虫都在重复做同一件事:
翻页、去重、限速、重试、并发、存储
如果每个爬虫都手写这些,会重复造无数轮子。框架层就是把这些公共逻辑封装起来。
为什么是这些框架:
| 框架 | 为什么是它 |
|---|---|
| Scrapy | 生态最成熟、文档最全、插件最多,Python 爬虫事实标准 |
| Crawlee | Apify 出品,反爬能力强,支持 Python 和 JS |
| Feapder | 国产,用法简洁,支持分布式 |
| Gerapy | 给 Scrapy 做可视化管理,不是爬虫框架本身 |
这层和"手写版"的关系:
手写版= 你自己写了请求 + 解析 + 调度 + 存储
Scrapy= 框架把请求、解析、调度、存储这些"公共骨架"都写好了,你只需要填"要抓哪些 URL"和"怎么解析"
判断标准:如果你发现"每个爬虫都要写一遍翻页、限速、去重"——说明该上框架了。
第 5 层:存储层
为什么有这一层:抓到的数据必须有地方放。放哪里,取决于"数据形态"和"访问方式"。
为什么是这些工具:
| 类型 | 工具 | 为什么是它 |
|---|---|---|
| 关系型 | MySQL / PostgreSQL | 数据字段固定、需要关联查询 |
| 文档型 | MongoDB | 字段不固定、结构灵活 |
| 缓存/去重 | Redis | URL 去重、任务队列,读写极快 |
| 搜索 | Elasticsearch | 数据量大、需要全文搜索 |
| 文件 | CSV / JSON / Parquet | 小规模、便于转储 |
| 对象存储 | S3 / OSS | 图片、PDF 等大文件 |
这层的核心矛盾是"灵活性 vs 查询能力":
JSON 文件:最灵活,但查不动
MongoDB:字段灵活,查询能力中等
MySQL:结构固定,查询能力最强
选型逻辑:数据量小 → 文件;字段不固定 → MongoDB;要复杂查询 → MySQL。
第 6 层:反爬 / 辅助层
为什么有这一层:这是爬虫和网站之间的"攻防战"层。网站会想办法识别和拦截爬虫,爬虫要绕过它。
这一层为什么不是"顺序的某一步":因为它横切在请求层和渲染层之上。任何一个请求,都可能需要经过反爬处理(加代理、加 UA、过验证码)。
为什么是这些工具:
| 类型 | 工具 / 做法 | 为什么是它 |
|---|---|---|
| 代理 IP | 代理池、隧道代理 | 防止单 IP 被封 |
| User-Agent | fake-useragent | 模拟不同浏览器 |
| Cookies 池 | 多账号轮换 | 绕过登录态限制 |
| 验证码 | 打码平台、OCR | 自动识别或转人工 |
| JS 逆向 | 补环境、AST、RPC | 破解签名、加密参数 |
| 指纹隐藏 | playwright-stealth、undetected-chromedriver | 绕过浏览器指纹检测 |
第 7 层:调度 / 分布式层
为什么有这一层:单机爬虫有性能上限。当数据量到百万、千万级时,必须用多台机器同时爬。
为什么是这些工具:
| 工具 | 为什么是它 |
|---|---|
| Scrapy-Redis | 让多个 Scrapy 实例共享一个队列,最简单实现分布式 |
| Airflow | 定时任务编排,让爬虫按计划跑 |
| Celery | 异步任务队列,适合做"任务分发 + 结果收集" |
| Docker + K8s | 集群化部署,让爬虫水平扩展 |
这层的核心矛盾是"单机 vs 分布式":
单机:简单,但有限
分布式:复杂,但可以无限扩展
判断标准:单机一天跑不完 → 该上分布式了。
四、各层之间的关系
这 7 层不是并列的,而是有明确的依赖和调用关系:
关系 1:框架层是"胶水"
框架(Scrapy)是核心中枢。它调用请求层(发请求)、渲染层(渲染 JS)、解析层(提取数据)、存储层(落库)。
你可以理解成:
没有框架 → 你手动把 1、2、3、5 层串起来
有框架 → 框架帮你串,你只填业务逻辑
关系 2:请求层和渲染层是"替代关系"
同一个目标页面,通常只用其中一个:
静态页面 → 请求层(快)
动态页面 → 渲染层(慢,但能拿到)
如果两者都用,说明页面部分动态、部分静态(比如第一页静态、后面靠滚动加载)。
关系 3:反爬层横切在请求和渲染之上
反爬层不是"顺序经过"的,而是"每次请求都要过一遍":
框架 → [反爬处理] → 请求层 → ...
框架 → [反爬处理] → 渲染层 → ...
关系 4:存储层是"终点"
所有数据最终都流向存储层。前面几层做的一切,都是为了让"数据正确、快速地流到存储层"。
关系 5:调度层是"指挥中心"
调度层不直接接触数据,它只负责调度框架层的运行——比如"每小时跑一次""分 10 台机器跑"。
五、总结
看完这 7 层,你会发现一个清晰的规律:
每一层的存在,都是为了解决"上一环暴露出来的一类问题"。
有"要发请求"的需求 → 请求层
请求回来是原始 HTML → 解析层
HTML 是空壳 → 渲染层
手写代码重复 → 框架层
数据要持久化 → 存储层
网站会拦截 → 反爬层
单机跑不完 → 调度层
这就是"生态圈"的本质:不是一堆工具堆在一起,而是一条"从目标网站到数据库"的完整流水线,每一层解决一个特定环节的问题。
一页速查
| 层 | 一句话职责 | 代表工具 |
|---|---|---|
| 请求层 | 发 HTTP 请求 | requests / httpx / aiohttp |
| 解析层 | 从 HTML/JSON 提取数据 | BeautifulSoup / lxml / parsel |
| 渲染层 | 执行 JS 拿动态 DOM | Playwright / Selenium |
| 框架层 | 组织流程、去重、调度 | Scrapy |
| 存储层 | 数据持久化 | MySQL / MongoDB / Redis |
| 反爬层 | 绕过网站限制 | 代理池 / 指纹隐藏 / JS 逆向 |
| 调度层 | 多机协作、定时任务 | Scrapy-Redis / Airflow |