别再只会requests+BeautifulSoup了!Scrapy核心架构+豆瓣Top250实战+避坑指南
摘要本文基于3年爬虫实战经验从“为什么用Scrapy”讲起拆解Scrapy的核心数据流与组件设计最后用豆瓣读书Top250实战展示完整开发流程。解决了requests单线程慢、反爬处理繁琐、数据存储混乱的痛点附settings.py配置、Item Pipeline、中间件的避坑指南代码可直接复制运行新手也能快速上手。前言刚学爬虫的时候我也觉得requestsBeautifulSoup天下无敌爬个新闻列表10行代码搞定爬个图片加个循环就行遇到反爬加个User-Agent和Referer完美解决。直到我爬了一个电商网站的10万条商品数据单线程爬了3天还没爬完遇到IP被封只能手动换代理换一次代理要重启程序数据存到CSV里格式混乱还要手动清洗程序崩溃了不知道从哪继续爬只能从头开始。后来我用了Scrapy同样的10万条数据用分布式爬了2小时就搞定了反爬自动处理数据自动存到MySQL崩溃了还能断点续爬。今天我把Scrapy的核心逻辑和实战经验分享出来帮你告别“只会requests”的尴尬。一、为什么要用Scrapy先明确一个结论requests适合爬小批量、结构简单的网站Scrapy适合爬大批量、有反爬、需要持久化的网站。对比项requestsBeautifulSoupScrapy并发能力单线程/手动多线程容易出错异步协程默认16并发可自由调整反爬处理手动加User-Agent、Referer、代理代码混乱中间件统一处理代码简洁可复用数据存储手动存CSV/MySQL格式混乱Item Pipeline统一处理支持多种存储方式断点续爬手动实现非常麻烦内置JOBDIR一行配置搞定扩展性差加个功能要改很多代码好组件化设计加个功能只需加个中间件或Pipeline二、Scrapy核心架构与数据流很多人看Scrapy的官方架构图觉得复杂其实核心逻辑非常简单从start_urls开始经过一系列组件最后yield item或request。2.1 简化版核心架构图Engine 引擎 (核心调度器)Scheduler 调度器 (存储待爬Request)Downloader 下载器 (下载网页)Spider 爬虫 (解析网页)Item 数据项 (解析出的有效数据)Request 新请求 (解析出的新链接)Item Pipeline 数据管道 (清洗/验证/存储数据)Downloader Middleware 下载中间件 (处理反爬User-Agent/Referer/代理)Spider Middleware 爬虫中间件 (处理Request/Item)2.2 核心组件详解2.2.1 Engine引擎Scrapy的大脑负责调度所有组件的工作不需要我们写代码直接用就行。2.2.2 Scheduler调度器存储待爬的Request支持优先级队列我们可以通过设置Request的priority参数来调整爬取顺序。2.2.3 Downloader下载器负责下载网页默认用异步协程速度非常快。我们可以通过Downloader Middleware来修改Request和Response。2.2.4 Spider爬虫我们写代码最多的地方负责解析网页yield item或新的Request。2.2.5 Item Pipeline数据管道负责处理Spider yield的item比如清洗数据、验证数据、存储数据到CSV/MySQL/MongoDB。可以设置多个Pipeline通过优先级来控制执行顺序。2.2.6 Middleware中间件分为Downloader Middleware和Spider Middleware是Scrapy最强大的功能之一用来统一处理反爬、修改Request/Item。三、实战爬取豆瓣读书Top250现在用Scrapy爬取豆瓣读书Top250展示完整的开发流程。3.1 环境准备# 安装Scrapypipinstallscrapy2.11.0# 最新稳定版# 验证安装scrapy version3.2 创建项目# 创建Scrapy项目scrapy startproject douban_book_top250# 进入项目目录cddouban_book_top250# 创建爬虫scrapy genspider douban_book book.douban.com3.3 定义Item在items.py中定义我们要爬取的数据importscrapyclassDoubanBookTop250Item(scrapy.Item):# 书名titlescrapy.Field()# 作者/译者/出版社/出版年份/定价infoscrapy.Field()# 评分ratingscrapy.Field()# 评价人数rating_numscrapy.Field()# 一句话简介quotescrapy.Field()# 详情页链接detail_urlscrapy.Field()3.4 编写Spider在spiders/douban_book.py中编写爬虫代码importscrapyfromdouban_book_top250.itemsimportDoubanBookTop250ItemclassDoubanBookSpider(scrapy.Spider):namedouban_bookallowed_domains[book.douban.com]# 豆瓣读书Top250的start_urlsstart_urls[https://book.douban.com/top250?start0]defparse(self,response):# 解析当前页的所有图书booksresponse.xpath(//div[classitem])forbookinbooks:itemDoubanBookTop250Item()# 书名item[title]book.xpath(.//div[classpl2]/a/title).get()# 详情页链接item[detail_url]book.xpath(.//div[classpl2]/a/href).get()# 作者/译者/出版社/出版年份/定价item[info]book.xpath(.//div[classpl]/text()).get().strip()# 评分item[rating]book.xpath(.//span[classrating_nums]/text()).get()# 评价人数item[rating_num]book.xpath(.//span[classpl]/text()).re_first(r\d)# 一句话简介item[quote]book.xpath(.//span[classinq]/text()).get()# yield itemyielditem# 解析下一页链接next_urlresponse.xpath(//span[classnext]/a/href).get()ifnext_url:# 构造下一页的Request回调函数还是parseyieldscrapy.Request(urlresponse.urljoin(next_url),callbackself.parse)3.5 配置settings.py在settings.py中配置反爬、并发、Pipeline等# Scrapy settings for douban_book_top250 project## For simplicity, this file contains only settings considered important or# commonly used. You can find more settings consulting the documentation:## https://docs.scrapy.org/en/latest/topics/settings.html# https://docs.scrapy.org/en/latest/topics/downloader-middleware.html# https://docs.scrapy.org/en/latest/topics/spider-middleware.htmlBOT_NAMEdouban_book_top250SPIDER_MODULES[douban_book_top250.spiders]NEWSPIDER_MODULEdouban_book_top250.spiders# 遵守robots.txt豆瓣的robots.txt禁止爬Top250所以设为FalseROBOTSTXT_OBEYFalse# 配置并发数默认16豆瓣反爬有点严设为2CONCURRENT_REQUESTS2# 配置下载延迟默认0设为2秒避免被封DOWNLOAD_DELAY2# 配置User-AgentUSER_AGENTMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36# 配置默认请求头DEFAULT_REQUEST_HEADERS{Accept:text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8,Accept-Language:zh-CN,zh;q0.9,en;q0.8,Referer:https://book.douban.com/,}# 配置Item Pipeline优先级越小越先执行ITEM_PIPELINES{douban_book_top250.pipelines.DoubanBookTop250Pipeline:300,}# 配置断点续爬取消注释即可使用# JOBDIR douban_book_job3.6 编写Item Pipeline在pipelines.py中编写数据清洗和存储代码importcsvclassDoubanBookTop250Pipeline:def__init__(self):# 打开CSV文件self.fileopen(douban_book_top250.csv,w,newline,encodingutf-8-sig)# 创建CSV写入器self.writercsv.writer(self.file)# 写入表头self.writer.writerow([书名,作者/译者/出版社/出版年份/定价,评分,评价人数,一句话简介,详情页链接])defprocess_item(self,item,spider):# 清洗数据去掉info中的换行符和多余空格item[info]item[info].replace(\n,).replace( , )# 写入CSVself.writer.writerow([item[title],item[info],item[rating],item[rating_num],item[quote],item[detail_url]])returnitemdefclose_spider(self,spider):# 关闭CSV文件self.file.close()3.7 运行爬虫# 运行爬虫scrapy crawl douban_book运行后会在当前目录生成douban_book_top250.csv文件里面就是我们爬取的豆瓣读书Top250的数据。四、避坑指南90%的人都会遇到4.1 settings.py的配置顺序Scrapy的settings.py配置有优先级从高到低依次是命令行参数-sSpider类中的custom_settingssettings.py文件Scrapy默认配置避坑如果在settings.py和custom_settings中都配置了同一个参数custom_settings会覆盖settings.py。4.2 Item Pipeline的优先级Item Pipeline的优先级越小越先执行比如ITEM_PIPELINES{douban_book_top250.pipelines.CleanPipeline:100,# 先执行douban_book_top250.pipelines.ValidatePipeline:200,# 再执行douban_book_top250.pipelines.StorePipeline:300,# 最后执行}避坑数据清洗和验证的Pipeline优先级要比存储的Pipeline小。4.3 yield和return的区别在Spider的parse函数中必须用yield不能用returnyield item把item交给Item Pipeline处理然后继续执行后面的代码yield request把request交给Scheduler处理然后继续执行后面的代码return直接结束parse函数后面的代码不会执行。4.4 xpath的坑text()只获取当前节点的文本不获取子节点的文本//text()获取当前节点和所有子节点的文本get()获取第一个匹配的结果getall()获取所有匹配的结果re_first()用正则表达式获取第一个匹配的结果re()用正则表达式获取所有匹配的结果。避坑如果要获取多个子节点的文本要用//text()然后用join()拼接起来。4.5 断点续爬的坑断点续爬的JOBDIR目录不能手动删除否则会丢失爬取进度。如果要重新爬取必须先删除JOBDIR目录。五、总结Scrapy不是“比requests难”的工具而是“比requests更适合大批量爬取”的工具。只要搞懂了Scrapy的核心架构和数据流你就能快速上手写出高效、稳定、可复用的爬虫。核心要点回顾为什么用Scrapy异步协程、中间件统一处理反爬、Item Pipeline统一处理数据、内置断点续爬核心架构Engine→Scheduler→Downloader→Spider→Item Pipeline实战流程创建项目→定义Item→编写Spider→配置settings.py→编写Item Pipeline→运行爬虫避坑指南配置顺序、Pipeline优先级、yield和return的区别、xpath的坑、断点续爬的坑。原创不易欢迎点赞收藏关注后续会更新Scrapy分布式爬取、Scrapy对接MySQL/MongoDB、Scrapy反爬进阶代理池、验证码识别等硬核教程