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。然后直接执行:
bash
pip install scrapy
安装完成后,可以检查版本:
bash
scrapy version
如果命令能正常输出版本信息,说明 Scrapy 已经安装成功。
5. 创建第一个 Scrapy 项目
Scrapy 通常不是单文件脚本的写法,而是按项目组织。
先创建项目:
bash
scrapy startproject myspider
进入项目目录:
bash
cd myspider
你会看到类似这样的结构:
text
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.py:
python
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.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把采集到的一条数据交给 Scrapy
7. 运行爬虫并查看结果
在项目根目录执行:
bash
scrapy crawl quotes
如果你想把结果直接导出成 JSON:
bash
scrapy crawl quotes -O quotes.json
导出成 CSV:
bash
scrapy crawl quotes -O quotes.csv
这一步非常重要,因为很多新手第一次接触 Scrapy 时,会突然意识到:原来我不用自己手写文件保存逻辑,Scrapy 已经帮我做好了。
8. response 到底是什么
在 parse(self, response) 里,response 就是服务器返回的页面响应对象。
你经常会用到这些能力:
python
response.url
response.status
response.text
response.css(...)
response.xpath(...)
比如:
python
def parse(self, response):
print(response.url)
print(response.status)
你可以把它理解成:请求完成后,Scrapy 把网页内容和相关信息都封装进了 response,供你继续解析。
9. 用 CSS 选择器提取数据
Scrapy 对 CSS 选择器支持很好,新手建议优先学这个。
还是看刚才那段代码:
python
quote.css("span.text::text").get()
quote.css("small.author::text").get()
quote.css("div.tags a.tag::text").getall()
这里有两个高频方法:
.get():取第一个匹配结果.getall():取所有匹配结果并返回列表
常见写法:
python
response.css("title::text").get()
response.css("a::attr(href)").getall()
response.css("img::attr(src)").getall()
如果页面里你想抓的是文本,就常用 ::text;如果你想抓链接或图片地址,就常用 ::attr(...)。
10. 也可以用 XPath
Scrapy 同样支持 XPath:
python
quote.xpath('.//span[@class="text"]/text()').get()
quote.xpath('.//small[@class="author"]/text()').get()
quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').getall()
那到底该学 CSS 还是 XPath?
我的建议是:
- 入门先用 CSS,语法更短
- 遇到复杂层级、兄弟节点、条件匹配时,再补 XPath
只会其中一种,也已经能做很多事。
11. 学会翻页抓取
单页采集只是开始,真正实用的场景通常都要翻页。
在 quotes.toscrape.com 首页底部有"下一页"链接,我们可以继续跟进:
python
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.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_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse)
这里最关键的一句是:
python
yield response.follow(next_page, callback=self.parse)
它的意思是:继续请求下一页,请求完成后仍然交给 parse() 处理。
这就是 Scrapy 很舒服的地方之一。你不需要自己手工拼接完整链接,也不用自己写复杂的循环控制。
12. 定义 Item,让数据结构更清晰
直接 yield {} 当然可以,但项目稍微大一点之后,定义 Item 会更规范。
先修改 items.py:
python
import scrapy
class QuoteItem(scrapy.Item):
text = scrapy.Field()
author = scrapy.Field()
tags = scrapy.Field()
然后在爬虫中使用:
python
import scrapy
from myspider.items import QuoteItem
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.css("div.quote"):
item = QuoteItem()
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()
yield item
Item 的好处是字段边界更清楚,后面写清洗逻辑、保存逻辑时也更统一。
13. 用 Pipeline 清洗数据
很多网页抓下来之后,并不是马上就能直接用。常见问题包括:
- 文本前后有空格
- 某些字段为空
- 日期格式不统一
- 同一条数据重复出现
这时就可以把清洗逻辑放进 pipelines.py。
例如:
python
class MyspiderPipeline:
def process_item(self, item, spider):
if item.get("text"):
item["text"] = item["text"].strip()
if item.get("author"):
item["author"] = item["author"].strip()
item["tags"] = [tag.strip() for tag in item.get("tags", [])]
return item
然后去 settings.py 启用它:
python
ITEM_PIPELINES = {
"myspider.pipelines.MyspiderPipeline": 300,
}
新手可以先记住一句话:Spider 负责抓,Pipeline 负责洗。
14. 常见配置项:新手最该先知道哪些
Scrapy 很强,但默认并不是"想怎么抓就怎么抓"。你至少应该知道下面几个配置项。
14.1 设置请求标识
有些网站会根据请求头判断请求来源。你可以在 settings.py 里设置:
python
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0 Safari/537.36"
14.2 控制抓取速度
不要对目标网站发太快的请求。新手阶段建议至少加一点延时:
python
DOWNLOAD_DELAY = 1
14.3 关闭 robots.txt 限制前先理解规则
很多教程会写:
python
ROBOTSTXT_OBEY = False
但你需要先知道这意味着什么。robots.txt 是网站声明抓取规则的地方。是否遵守,要根据你的使用场景、目标站点规则和合规要求来判断。新手不要一上来就默认无视规则。
14.4 导出中文时避免乱码
如果你要导出中文 JSON,经常会加:
python
FEED_EXPORT_ENCODING = "utf-8"
这能减少导出文件中文乱码的问题。
15. 一个更像真实项目的完整示例
下面给你一个稍完整一点的爬虫,把抓取、翻页和字段提取放在一起:
python
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
allowed_domains = ["quotes.toscrape.com"]
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.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_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse)
这个版本已经覆盖了初学者最常用的几个动作:
- 进入起始页
- 遍历列表块
- 提取文本、作者、标签、详情链接
- 继续翻页
16. 新手最容易踩的坑
刚学 Scrapy 时,下面这些问题非常常见:
16.1 选择器写对了,但取不到数据
原因可能包括:
- 页面结构和你想的不一样
- 内容在 JavaScript 运行后才出现
- 你选中的节点层级不对
- 属性名或类名写错
先做两件事:
- 在浏览器开发者工具里重新检查元素
- 用
scrapy shell 网址进入交互环境测试选择器
例如:
bash
scrapy shell https://quotes.toscrape.com/
进入后可以直接测试:
python
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 原生就支持把数据导出为:
- JSON
- CSV
- JSON Lines
- XML
如果你自己再扩展 Pipeline,还可以保存到:
- MySQL
- PostgreSQL
- MongoDB
- Redis
- Elasticsearch
17.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 就不会再显得抽象。