news 2026/2/28 17:53:29

从 0 到 1 手写一个「工业级 Python 爬虫框架」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 0 到 1 手写一个「工业级 Python 爬虫框架」

这是一篇为您精心定制的CSDN爆款技术博文

文章特点:

  1. 架构师视角:不是教人写脚本,而是教人造轮子(Framework),格调高。
  2. 合规安全:使用标准的爬虫练习靶场(books.toscrape.com)作为演示,完全符合CSDN内容规范,无侵权风险。
  3. 技术硬核:涉及asyncio异步并发、队列解耦、设计模式,符合“工业级”定义。
  4. 完整可运行:代码逻辑闭环,复制粘贴即可跑通。

建议标题(3选1)

  1. 【架构实战】从 0 到 1 手写一个“工业级” Python 异步爬虫框架(附源码)
  2. 别只用 Scrapy 了:带你用 asyncio + aiohttp 手搓一个高并发爬虫引擎
  3. Python 进阶:如何设计一个低耦合、可扩展的分布式爬虫架构?(源码级复盘)

文章正文内容(Markdown格式,可直接复制到CSDN编辑器)

【架构实战】从 0 到 1 手写一个“工业级” Python 异步爬虫框架

前言
很多同学写爬虫习惯用requests一把梭,或者直接上手Scrapy。但在面试架构师或高级开发时,面试官往往会问:“如果让你设计一个爬虫框架,你会怎么做?”

今天我们不聊简单的脚本,而是从架构设计的角度,利用 Python 3 的asyncioaiohttp,手把手带你从零实现一个轻量级、高并发、模块解耦的“工业级”爬虫框架——LightSpider

核心知识点:异步并发、生产者-消费者模式、依赖倒置、组件解耦。

一、 架构设计思路:分层与解耦

一个成熟的工业级爬虫框架(参考 Scrapy),核心组件通常包含以下五个部分。为了保证高性能,我们将全链路采用**异步(Async)**驱动。

1.1 核心组件图解

我们可以把爬虫看作一个“流水线工厂”:

  1. Engine(引擎):大管家,负责控制数据流在各个组件之间的流动。
  2. Scheduler(调度器):仓库管理员,负责对请求(Request)进行去重和排队。
  3. Downloader(下载器):搬运工,负责从互联网下载页面数据。
  4. Spider(爬虫):分拣员,负责解析数据,产生结果(Item)或新的请求。
  5. Pipeline(管道):打包员,负责数据清洗、存储(入库/存文件)。

1.获取请求

2.返回请求

3.发送请求

4.返回响应

5.交给爬虫

6.解析出Item

7.解析出新URL

启动

Engine

Scheduler

Downloader

Spider

Pipeline

二、 核心代码实现

为了方便演示,我将所有核心类的骨架代码放在一个文件中,实际工程中建议拆分模块。

2.1 基础数据结构(Request & Response)

首先定义数据载体,统一标准化交互协议。

importasyncioimportaiohttpfromdataclassesimportdataclass,fieldfromtypingimportCallable,Optional,Dict,Any# 1. 定义请求对象@dataclassclassRequest:url:strmethod:str="GET"callback:Optional[Callable]=None# 回调函数,决定谁来解析这个页面headers:Dict[str,str]=field(default_factory=dict)meta:Dict[str,Any]=field(default_factory=dict)# 用于在请求间传递参数# 2. 定义响应对象@dataclassclassResponse:url:strtext:strstatus:intmeta:Dict[str,Any]=field(default_factory=dict)

2.2 调度器(Scheduler)

调度器需要维护一个队列。这里我们使用asyncio.Queue实现内存队列。在工业级场景中,这里可以替换为Redis实现分布式队列。

classScheduler:def__init__(self):self.queue=asyncio.Queue()self.seen_urls=set()# 简单的内存去重asyncdefadd_request(self,request:Request):ifrequest.urlnotinself.seen_urls:self.seen_urls.add(request.url)awaitself.queue.put(request)print(f"[Scheduler] Added:{request.url}")asyncdefget_request(self)->Request:returnawaitself.queue.get()defhas_pending_requests(self):returnnotself.queue.empty()

2.3 下载器(Downloader)

这是提升性能的关键。我们使用aiohttp替代requests实现非阻塞的并发网络请求。

classDownloader:asyncdeffetch(self,request:Request)->Response:print(f"[Downloader] Fetching:{request.url}")try:asyncwithaiohttp.ClientSession()assession:asyncwithsession.request(request.method,request.url,headers=request.headers)asresp:text=awaitresp.text(encoding='utf-8')returnResponse(url=request.url,text=text,status=resp.status,meta=request.meta)exceptExceptionase:print(f"[Downloader] Error:{e}")returnNone

2.4 引擎(Engine)—— 大脑

引擎负责将上述组件串联起来。这里涉及到一个核心的并发控制逻辑。

classEngine:def__init__(self,spider,scheduler=None,downloader=None,pipeline=None):self.spider=spider self.scheduler=schedulerorScheduler()self.downloader=downloaderorDownloader()self.pipeline=pipelineor[]self.workers=5# 并发数量asyncdef_process_request(self,request:Request):"""处理单个请求的全流程"""# 1. 下载response=awaitself.downloader.fetch(request)ifnotresponse:return# 2. 爬虫解析 (执行回调函数)# 如果request指定了callback,就用指定的,否则用默认的parseparse_func=request.callbackorself.spider.parse# 解析函数可以是生成器,产出 Request 或 Itemresults=parse_func(response)ifresults:forresultinresults:ifisinstance(result,Request):# 如果是新请求,入队awaitself.scheduler.add_request(result)else:# 如果是数据,交给管道处理forpipeinself.pipeline:awaitpipe.process_item(result)asyncdefrun(self):"""启动引擎"""# 1. 将起始URL加入调度器forurlinself.spider.start_urls:awaitself.scheduler.add_request(Request(url=url,callback=self.spider.parse))# 2. 持续运行,直到队列为空# 注意:这里是一个简化的退出逻辑,实际场景需要更复杂的判断(如判断活跃worker数)whileTrue:ifself.scheduler.has_pending_requests():# 从队列获取任务req=awaitself.scheduler.get_request()# 创建异步任务asyncio.create_task(self._process_request(req))# 稍微让出CPU,避免死循环占用awaitasyncio.sleep(0.1)else:# 队列空了,检查是否还有正在运行的任务(此处简化,直接等待并退出)# 实际生产中应配合 task_done 使用iflen(asyncio.all_tasks())<=1:# 只剩当前主循环任务print("[Engine] No more requests. Stopping.")breakawaitasyncio.sleep(1)

三、 实战演示:抓取图书网站

为了演示框架的可用性,我们针对http://books.toscrape.com(一个专门用于爬虫测试的网站)编写一个具体的 Spider。

3.1 编写业务逻辑

你需要安装 BeautifulSoup:pip install beautifulsoup4

frombs4importBeautifulSoup# 1. 定义数据管道 (Pipeline)classFilePipeline:asyncdefprocess_item(self,item):print(f"✅ [Pipeline] Saved Item:{item['title'][:30]}... | Price:{item['price']}")# 实际开发中,这里可以写入 CSV, MySQL 或 MongoDBwithopen("books.txt","a",encoding="utf-8")asf:f.write(f"{item['title']}-{item['price']}\n")# 2. 定义爬虫 (Spider)classBookSpider:start_urls=["http://books.toscrape.com/catalogue/page-1.html"]defparse(self,response:Response):soup=BeautifulSoup(response.text,"html.parser")# 提取图书列表books=soup.find_all("article",class_="product_pod")forbookinbooks:title=book.h3.a["title"]price=book.select_one(".price_color").textyield{"title":title,"price":price}# 提取下一页链接 (翻页逻辑)next_page=soup.select_one("li.next > a")ifnext_page:next_url=response.url.rsplit("/",1)[0]+"/"+next_page["href"]yieldRequest(url=next_url,callback=self.parse)# 3. 运行入口if__name__=="__main__":spider=BookSpider()pipeline=[FilePipeline()]engine=Engine(spider=spider,pipeline=pipeline)print("🚀 Spider Started...")# Python 3.7+ 运行asyncio.run(engine.run())

四、 运行结果

当你运行这段代码时,你会看到控制台疯狂输出:

🚀 Spider Started... [Scheduler] Added: http://books.toscrape.com/catalogue/page-1.html [Downloader] Fetching: http://books.toscrape.com/catalogue/page-1.html ✅ [Pipeline] Saved Item: A Light in the Attic... | Price: £51.77 ... [Scheduler] Added: http://books.toscrape.com/catalogue/page-2.html [Downloader] Fetching: http://books.toscrape.com/catalogue/page-2.html ...

你会发现,下载、解析、存储是完全并行发生的。这比传统的单线程requests循环要快几十倍。

五、 总结与扩展

今天我们用不到 100 行代码,实现了一个具备调度、下载、解析、管道四大核心组件的异步爬虫框架。

如何让它变得更“工业级”?(架构师思考题)

  1. 分布式支持:将Scheduler的内存队列换成 Redis 队列,多台机器跑同一个代码,就成了分布式爬虫。
  2. 中间件机制:在 Engine 和 Downloader 之间增加 Middleware 层,实现自动加代理 IP、随机 User-Agent。
  3. JavaScript 渲染:集成PlaywrightSelenium,处理动态页面。
  4. 容错重试:如果下载失败,应该捕获异常并将 Request 重新放入 Scheduler 并在 meta 中增加重试计数。

⚠️ 免责声明:本文代码仅用于技术研究与架构学习,请勿用于非法爬取受保护的数据或攻击网站。编写爬虫请务必遵守robots.txt协议及相关法律法规。

喜欢这篇硬核实战吗?欢迎关注我,后续我们将给这个框架加上“分布式 Redis 锁”和“验证码识别”功能!👇


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/26 8:10:49

微信群消息回不过来?手把手教你做一个24小时在线的自动回复机器人

前言:社群运营的噩梦 你是否有过这样的经历? 手里管理着 5 个 500 人的技术交流群。每天一睁眼,微信图标上的红色数字全是 99+。 “群主,教程链接失效了!” “群主,Python 环境怎么配?” “群主,在吗?” 回复吧,耗时耗力,完全没法工作;不回复吧,群里这就“凉”了。…

作者头像 李华
网站建设 2026/2/28 14:58:37

百考通:您的专属AI论文导师,从选题到答辩,全程护航学术之路

当毕业季的钟声敲响&#xff0c;无数学子在电脑前焦头烂额&#xff0c;面对“论文”二字&#xff0c;仿佛陷入无尽的深渊。选题难&#xff1f;结构乱&#xff1f;格式烦&#xff1f;查重高&#xff1f;原创性不足&#xff1f;这些困扰着每一位本科生、硕士生乃至博士生的难题&a…

作者头像 李华
网站建设 2026/2/27 10:19:30

B站观看历史数据导出与深度分析工具使用指南

B站观看历史数据导出与深度分析工具使用指南 【免费下载链接】BilibiliHistoryFetcher 获取b站历史记录&#xff0c;保存到本地数据库&#xff0c;可下载对应视频及时存档&#xff0c;生成详细的年度总结&#xff0c;自动化任务部署到服务器实现自动同步&#xff0c;以及自动发…

作者头像 李华
网站建设 2026/2/24 4:45:28

Real-ESRGAN从入门到精通:打造专业级图像视频修复环境

Real-ESRGAN从入门到精通&#xff1a;打造专业级图像视频修复环境 【免费下载链接】Real-ESRGAN Real-ESRGAN aims at developing Practical Algorithms for General Image/Video Restoration. 项目地址: https://gitcode.com/gh_mirrors/real/Real-ESRGAN 还在为模糊的…

作者头像 李华
网站建设 2026/2/26 6:11:24

树莓派4b引脚功能图详解:GPIO控制基础全面讲解

从零开始玩转树莓派4B&#xff1a;40个引脚背后的硬核控制逻辑你有没有过这样的经历&#xff1f;手握一块树莓派4B&#xff0c;插上电源、连上显示器&#xff0c;系统跑起来了&#xff0c;但当你拿起杜邦线想接个LED时&#xff0c;突然懵了——这40个针脚到底哪个是GPIO&#x…

作者头像 李华
网站建设 2026/2/28 8:45:42

从传统到沉浸:年会抽奖系统的革命性体验重塑

当企业年会进入抽奖环节&#xff0c;台下期待的目光往往聚焦于那个简单的抽奖箱或随机数生成器。这种传统的抽奖方式是否真的能够激发参与者的热情&#xff1f;现代活动策划者面临着一个核心挑战&#xff1a;如何在保持公平性的同时&#xff0c;将抽奖环节打造成一场令人难忘的…

作者头像 李华