Python Scrapy 入门教程从零学会抓取和解析网页数据很多 Python 初学者学完基础语法后都会遇到一个很实际的问题怎么把网页里的数据稳定地提取下来变成自己能处理的结构化数据如果你只是偶尔抓一个页面用requests BeautifulSoup当然可以但当你想抓取多个页面、自动跟进链接、统一清洗字段、导出成 JSON 或 CSV甚至把数据存进数据库时Scrapy会明显更省事。Scrapy是 Python 生态里非常经典的爬虫框架。它不只是“下载网页源码”而是把发请求、收响应、解析数据、跟踪链接、导出结果、去重、限速、日志管理这一整套流程都组织好了。这篇文章面向新手目标很明确让你理解 Scrapy 是什么带你从零创建一个 Scrapy 项目学会抓取网页、解析字段、翻页采集、导出数据告诉你 Scrapy 除了抓文章标题之外还能做什么学完后你至少能独立写出一个基础可用的网页数据采集脚本。1. Scrapy 是什么Scrapy是一个用于抓取网站并提取结构化数据的 Python 框架。你可以把它理解成一个专门为“网页采集”准备好的工程化工具箱。相比只写一个简单脚本Scrapy 的优势在于它已经帮你解决了很多重复问题比如请求调度并发抓取自动跟踪链接页面解析数据导出日志输出重试与超时去重和限速也就是说Scrapy 更适合做“持续抓取”和“多页面采集”而不只是一次性的实验代码。2. Scrapy 适合哪些场景对新手来说最适合先用 Scrapy 解决的通常是下面这些任务抓取资讯站点的标题、链接、发布时间采集商品列表页中的名称、价格、销量、详情页地址批量抓取博客、论坛、文档站中的内容摘要采集招聘网站中的岗位名称、城市、薪资范围采集分页数据并导出成 JSON、CSV、Excel 可再处理的数据如果你的目标是“从很多网页里提取重复结构的数据”Scrapy 基本就是合适的工具。3. Scrapy 和requests BeautifulSoup有什么区别很多新手会问我已经会requests和BeautifulSoup为什么还要学 Scrapy可以这样理解requests负责发请求BeautifulSoup负责解析 HTMLScrapy则把请求、解析、调度、导出、翻页、日志这些能力打包成了一个框架如果只是抓 1 个页面requests BeautifulSoup更轻量。如果要抓几十页、几百页或者想要把项目组织得更清晰、可复用、可扩展Scrapy 往往更合适。4. 安装 Scrapy先确保你已经安装了 Python。然后直接执行pipinstallscrapy安装完成后可以检查版本scrapy version如果命令能正常输出版本信息说明 Scrapy 已经安装成功。5. 创建第一个 Scrapy 项目Scrapy 通常不是单文件脚本的写法而是按项目组织。先创建项目scrapy startproject myspider进入项目目录cdmyspider你会看到类似这样的结构myspider/ ├── scrapy.cfg └── myspider/ ├── __init__.py ├── items.py ├── middlewares.py ├── pipelines.py ├── settings.py └── spiders/几个最常见的文件先记住spiders/放爬虫代码items.py定义要采集的数据字段pipelines.py对采集结果做清洗、保存、去重等处理settings.py配置请求头、并发、延时、导出编码等刚开始你不需要把每个文件都学透先会写spiders/里的爬虫就够了。6. 先写一个最小可运行的爬虫下面我们用一个经典练习站点https://quotes.toscrape.com/来演示。这个站点专门给爬虫教程使用页面结构简单很适合新手练手。在spiders目录下新建文件quotes_spider.pyimportscrapyclassQuotesSpider(scrapy.Spider):namequotesstart_urls[https://quotes.toscrape.com/]defparse(self,response):forquoteinresponse.css(div.quote):yield{text:quote.css(span.text::text).get(),author:quote.css(small.author::text).get(),tags:quote.css(div.tags a.tag::text).getall(),}这段代码先不要急着背先理解它在做什么name是爬虫名字后面运行时要用start_urls是起始页面列表parse()是默认解析函数response.css(...)用 CSS 选择器定位网页元素yield把采集到的一条数据交给 Scrapy7. 运行爬虫并查看结果在项目根目录执行scrapy crawl quotes如果你想把结果直接导出成 JSONscrapy crawl quotes-Oquotes.json导出成 CSVscrapy crawl quotes-Oquotes.csv这一步非常重要因为很多新手第一次接触 Scrapy 时会突然意识到原来我不用自己手写文件保存逻辑Scrapy 已经帮我做好了。8.response到底是什么在parse(self, response)里response就是服务器返回的页面响应对象。你经常会用到这些能力response.url response.status response.text response.css(...)response.xpath(...)比如defparse(self,response):print(response.url)print(response.status)你可以把它理解成请求完成后Scrapy 把网页内容和相关信息都封装进了response供你继续解析。9. 用 CSS 选择器提取数据Scrapy 对 CSS 选择器支持很好新手建议优先学这个。还是看刚才那段代码quote.css(span.text::text).get()quote.css(small.author::text).get()quote.css(div.tags a.tag::text).getall()这里有两个高频方法.get()取第一个匹配结果.getall()取所有匹配结果并返回列表常见写法response.css(title::text).get()response.css(a::attr(href)).getall()response.css(img::attr(src)).getall()如果页面里你想抓的是文本就常用::text如果你想抓链接或图片地址就常用::attr(...)。10. 也可以用 XPathScrapy 同样支持 XPathquote.xpath(.//span[classtext]/text()).get()quote.xpath(.//small[classauthor]/text()).get()quote.xpath(.//div[classtags]/a[classtag]/text()).getall()那到底该学 CSS 还是 XPath我的建议是入门先用 CSS语法更短遇到复杂层级、兄弟节点、条件匹配时再补 XPath只会其中一种也已经能做很多事。11. 学会翻页抓取单页采集只是开始真正实用的场景通常都要翻页。在quotes.toscrape.com首页底部有“下一页”链接我们可以继续跟进importscrapyclassQuotesSpider(scrapy.Spider):namequotesstart_urls[https://quotes.toscrape.com/]defparse(self,response):forquoteinresponse.css(div.quote):yield{text:quote.css(span.text::text).get(),author:quote.css(small.author::text).get(),tags:quote.css(div.tags a.tag::text).getall(),}next_pageresponse.css(li.next a::attr(href)).get()ifnext_page:yieldresponse.follow(next_page,callbackself.parse)这里最关键的一句是yieldresponse.follow(next_page,callbackself.parse)它的意思是继续请求下一页请求完成后仍然交给parse()处理。这就是 Scrapy 很舒服的地方之一。你不需要自己手工拼接完整链接也不用自己写复杂的循环控制。12. 定义 Item让数据结构更清晰直接yield {}当然可以但项目稍微大一点之后定义Item会更规范。先修改items.pyimportscrapyclassQuoteItem(scrapy.Item):textscrapy.Field()authorscrapy.Field()tagsscrapy.Field()然后在爬虫中使用importscrapyfrommyspider.itemsimportQuoteItemclassQuotesSpider(scrapy.Spider):namequotesstart_urls[https://quotes.toscrape.com/]defparse(self,response):forquoteinresponse.css(div.quote):itemQuoteItem()item[text]quote.css(span.text::text).get()item[author]quote.css(small.author::text).get()item[tags]quote.css(div.tags a.tag::text).getall()yielditemItem的好处是字段边界更清楚后面写清洗逻辑、保存逻辑时也更统一。13. 用 Pipeline 清洗数据很多网页抓下来之后并不是马上就能直接用。常见问题包括文本前后有空格某些字段为空日期格式不统一同一条数据重复出现这时就可以把清洗逻辑放进pipelines.py。例如classMyspiderPipeline:defprocess_item(self,item,spider):ifitem.get(text):item[text]item[text].strip()ifitem.get(author):item[author]item[author].strip()item[tags][tag.strip()fortaginitem.get(tags,[])]returnitem然后去settings.py启用它ITEM_PIPELINES{myspider.pipelines.MyspiderPipeline:300,}新手可以先记住一句话Spider 负责抓Pipeline 负责洗。14. 常见配置项新手最该先知道哪些Scrapy 很强但默认并不是“想怎么抓就怎么抓”。你至少应该知道下面几个配置项。14.1 设置请求标识有些网站会根据请求头判断请求来源。你可以在settings.py里设置USER_AGENTMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0 Safari/537.3614.2 控制抓取速度不要对目标网站发太快的请求。新手阶段建议至少加一点延时DOWNLOAD_DELAY114.3 关闭robots.txt限制前先理解规则很多教程会写ROBOTSTXT_OBEYFalse但你需要先知道这意味着什么。robots.txt是网站声明抓取规则的地方。是否遵守要根据你的使用场景、目标站点规则和合规要求来判断。新手不要一上来就默认无视规则。14.4 导出中文时避免乱码如果你要导出中文 JSON经常会加FEED_EXPORT_ENCODINGutf-8这能减少导出文件中文乱码的问题。15. 一个更像真实项目的完整示例下面给你一个稍完整一点的爬虫把抓取、翻页和字段提取放在一起importscrapyclassQuotesSpider(scrapy.Spider):namequotesallowed_domains[quotes.toscrape.com]start_urls[https://quotes.toscrape.com/]defparse(self,response):forquoteinresponse.css(div.quote):yield{text:quote.css(span.text::text).get(default).strip(),author:quote.css(small.author::text).get(default).strip(),tags:quote.css(div.tags a.tag::text).getall(),detail_url:response.urljoin(quote.css(span a::attr(href)).get(default)),}next_pageresponse.css(li.next a::attr(href)).get()ifnext_page:yieldresponse.follow(next_page,callbackself.parse)这个版本已经覆盖了初学者最常用的几个动作进入起始页遍历列表块提取文本、作者、标签、详情链接继续翻页16. 新手最容易踩的坑刚学 Scrapy 时下面这些问题非常常见16.1 选择器写对了但取不到数据原因可能包括页面结构和你想的不一样内容在 JavaScript 运行后才出现你选中的节点层级不对属性名或类名写错先做两件事在浏览器开发者工具里重新检查元素用scrapy shell 网址进入交互环境测试选择器例如scrapy shell https://quotes.toscrape.com/进入后可以直接测试response.css(title::text).get()这是定位问题最快的方法之一。16.2 页面明明能打开但 Scrapy 抓不到完整内容这通常是因为目标页面的数据是前端 JavaScript 动态渲染出来的而 Scrapy 默认抓到的是原始 HTML 响应。这时你有几种思路先在浏览器网络面板里找真实接口直接抓接口数据配合scrapy-playwright处理需要渲染的页面对确实只依赖静态 HTML 的站点优先直接用 Scrapy对新手来说先学会抓静态页面再处理动态页面学习曲线会平很多。16.3 导出的数据重复原因往往是翻页逻辑写错同一个链接被多次跟进详情页和列表页重复产出同一条记录解决思路通常是检查next_page逻辑用唯一字段去重在 Pipeline 中做重复判断17. Scrapy 除了抓网页标题还能做什么很多新手误以为 Scrapy 只能“抓文章标题”。其实它能做的事情远不止这些。17.1 采集结构化业务数据比如商品名称、价格、库存、评分招聘岗位、地点、经验要求、薪资区间博客标题、作者、发布时间、标签课程名称、章节、讲师、简介17.2 批量跟进详情页很多网站首页只给列表摘要真正的详细信息在详情页里。Scrapy 很适合这种“列表页拿链接再进入详情页补字段”的流程。17.3 构建数据清洗流水线抓取不是终点。你可以在 Scrapy 里顺手做文本清洗字段标准化去重时间格式转换金额单位统一17.4 导出到多种格式Scrapy 原生就支持把数据导出为JSONCSVJSON LinesXML如果你自己再扩展 Pipeline还可以保存到MySQLPostgreSQLMongoDBRedisElasticsearch17.5 做定时采集任务Scrapy 项目很适合接入定时任务比如每天抓一次新闻、每小时抓一次价格、每周抓一次岗位变化。它不只是“写完跑一次”的脚本也可以发展成长期运行的数据采集工程。18. 学 Scrapy 时要有的正确认知Scrapy 很强但它不是万能的。你要早点建立这几个认知它擅长静态页面和结构化采集它不负责替你绕过网站风控它不保证所有 JavaScript 页面都能直接抓它是工程框架不只是几行演示代码也就是说学习 Scrapy 的重点不是死记 API而是建立一个完整思路找页面结构写选择器提取字段跟进分页或详情页清洗和保存结果只要这个流程打通后面你抓不同网站时变化的主要只是选择器和字段而不是整个方法论。19. 给新手的学习路线如果你刚开始学 Scrapy我建议按下面顺序练习先抓单页标题、链接、文本再练列表页循环提取再加翻页再进入详情页补充字段再学习 Item、Pipeline、Settings最后再接触动态渲染页面和数据库存储不要一上来就挑战特别复杂的网站。先把简单站点做通成就感会高很多理解也更扎实。20. 总结如果你想系统学习 Python 爬虫Scrapy是非常值得投入时间的框架。它的价值不只是“能抓网页”而是把网页采集这件事从零散脚本提升成了一个更规范、更稳定、可扩展的工程流程。对新手来说一旦你学会了创建项目编写 Spider用 CSS 或 XPath 解析字段实现翻页抓取用 Pipeline 清洗数据导出结果你就已经具备了独立完成基础网页数据采集任务的能力。最后提醒一句在实际抓取网站数据时一定要关注目标网站的使用规则、访问频率和合规要求。技术能力越强越要有边界意识。如果你刚准备开始动手最推荐的练习方式就是自己创建一个 Scrapy 项目抓取quotes.toscrape.com这样的练习站点把本文里的例子完整跑一遍。只要你亲手跑通一次Scrapy 就不会再显得抽象。