
每当我们提到“爬虫”,绝大多数 Python 开发者脑海中浮现的第一个名字就是 Scrapy。它强大、成熟、生态丰富,几乎能解决生产环境中 90% 以上的问题。但正是这种“开箱即用”的便利,反而让很多初学者甚至中级开发者对爬虫的核心原理产生了隔阂感——我们学会了用scrapy crawl,却说不清爬虫的本质到底是什么。事实上,爬虫最底层的本质极其简单,可以浓缩为一个公式:爬虫 = HTTP 客户端 + 递归任务调度这意味着,只要你能够:发送一个 HTTP 请求并拿到响应;从响应中解析出数据和新链接;把新链接放入队列,不断重复上述过程;你就已经实现了一个“爬虫”。至于并发、去重、限速、持久化、错误重试等,统统都是在这个内核之上的“增强功能”。本文的目标是:从零开始,仅使用 Python 标准库,构建一个最小化的、可运行的爬虫框架。我们会严格遵循“抽象”与“实现”分离的设计原则,定义三个核心抽象类 ——Fetcher、Parser、Scheduler,然后基于它们实现单线程递归爬取。随后,我们会深入讨论robots.txt的本地缓存策略,最后指出从单线程到并发爬虫的演进路径。阅读完本文后,你不仅会拥有一个自己亲手写出的爬虫框架雏形,更会对所有爬虫框架(无论是 Scrapy、PySpider 还是定制化系统)的底层设计哲学有豁然开朗的理解。目录第一章:爬虫的“第一性原理”1.1 万物始于 URL1.2 HTTP 客户端:爬虫的“手”与“脚”1.3 递归任务调度:爬虫的“大脑”第二章:标准库中的兵器谱第三章:抽象类设计——三大支柱3.1 Fetcher(抓取器)3.2 Parser(解析器)3.3 Scheduler(调度器)3.4 为什么分成三个抽象类?第四章:具体实现——从抽象到落地4.1 工程结构4.2 Fetcher 实现4.3 Parser 实现4.4 Scheduler 实现4.5 组装爬虫:Spider 引擎第五章:robots.txt 的本地缓存策略5.1 为什么需要 robots.txt?5.2 标准库解析 robots.txt5.3 缓存设计思路5.4 实现 RobotsCache 类5.5 集成到 Fetcher 中第六章:单线程的局限与并发化演进6.1 单线程爬虫的瓶颈6.2 多线程方案6.3 异步 I/O 方案(asyncio + aiohttp)6.4 分布式演进第七章:完整实战——爬取一个技术博客7.1 编写示例脚本7.2 运行与输出7.3 数据持久化扩展第八章:性能优化与反爬对抗8.1 性能优化策略8.2 常见反爬措施与应对第九章:总结与展望9.1 我们做了什么9.2 这套框架的价值9.3 下一步改进方向第一章:爬虫的“第一性原理”1.1 万物始于 URL任何爬虫的起点都是一个或一组初始 URL。从计算机科学的角度看,整个万维网可以抽象为一个有向图:每个页面是一个节点,页面中的超链接是边。爬虫的任务就是从这个图中的某些节点出发,沿着边遍历,并在遍历过程中收集信息。于是,爬虫的核心问题变成了:如何从当前节点(页面)获取邻接节点(链接)?如何避免重复访问同一个节点(去重)?以什么顺序遍历图(BFS / DFS / 优先级)?如何限制遍历的边界(域名限制、深度限制、数量限制)?而这一切的物理基础,仅仅是HTTP 协议。