Scrapy 爬虫的最小闭环只有五步:创建项目、发送请求、解析字段、跟随下一页、导出结果。初学时先用公开练习页面跑通这个闭环,再考虑并发、代理或分布式,学习效率会更高。

你会用 requests 抓到一页 HTML,却不知道怎样把脚本变成可维护项目;或者写出了 Spider,但翻页后数据重复、字段为空。本文基于 Python 3 与 Scrapy 的常见项目结构,用一个公开练习列表页讲清请求、CSS 选择器、Item、翻页和 JSON 导出。今天这篇文章,编程狮带你完成第一个能运行、能检查、也知道边界的 Scrapy 爬虫。
一、创建 Scrapy 爬虫项目与运行环境
Scrapy 是一个面向网络抓取的 Python 框架。它把请求调度、响应解析、数据管道和并发控制拆成不同组件,适合从一次性脚本升级到可维护项目。
先创建独立虚拟环境并安装 Scrapy:
python -m venv .venv
Windows 激活命令:
.venv\Scripts\activate
python -m pip install scrapy
macOS 与 Linux 激活命令:
source .venv/bin/activate
python -m pip install scrapy
然后创建项目:
scrapy startproject w3cschool_demo
cd w3cschool_demo
scrapy genspider books books.toscrape.com
项目中的 spiders 放抓取规则,items.py 定义数据结构,pipelines.py 处理清洗和保存,settings.py 管并发、延迟与请求头。Python 基础不扎实时,先补一遍 Python3 基础教程,会更容易理解类、生成器和字典。
二、发送请求并确认响应是否正确
Spider 的 start_urls 会生成初始请求,parse 方法接收响应。先只打印状态码和页面标题,确认域名、编码与响应内容正确,再开始写复杂选择器。
import scrapy
class BooksSpider(scrapy.Spider):
name = "books"
allowed_domains = ["books.toscrape.com"]
start_urls = ["https://books.toscrape.com/"]
def parse(self, response):
self.logger.info("status=%s url=%s", response.status, response.url)
title = response.css("title::text").get(default="").strip()
self.logger.info("page title=%s", title)
运行命令如下:
scrapy crawl books
如果状态码不是 200,先检查 robots.txt、访问频率、域名和网络,不要立即加入伪装请求头或代理。Scrapy 爬虫应遵守目标网站规则,只抓取允许公开访问的数据,并设置合理延迟。
HTTP 请求机制不熟悉时,Python requests 教程 能帮助你先理解请求、响应、状态码和请求头,再回来看 Scrapy 的调度层。
三、用 CSS 选择器解析列表字段
练习页面中,每本书位于 article.product_pod 元素。先用浏览器开发者工具找到重复的列表容器,再逐条提取标题、价格和详情地址。
import scrapy
class BooksSpider(scrapy.Spider):
name = "books"
allowed_domains = ["books.toscrape.com"]
start_urls = ["https://books.toscrape.com/"]
def parse(self, response):
for card in response.css("article.product_pod"):
yield {
"title": card.css("h3 a::attr(title)").get(default="").strip(),
"price": card.css("p.price_color::text").get(default="").strip(),
"url": response.urljoin(card.css("h3 a::attr(href)").get()),
}
get 取第一个结果,getall 返回全部结果。default 可以避免选择器未命中时立刻对 None 调用 strip。response.urljoin 会基于当前页面补全相对地址,比手工拼接域名可靠。
💡 小提示:选择器先在
scrapy shell URL中测试。每次只确认一个字段,命中后再写进 Spider,排错会比反复运行整个项目更快。
四、跟随下一页并避免重复抓取
列表页通常通过“下一页”链接翻页。Scrapy 会自动对请求去重,因此最简单的做法是提取 next 链接并 yield response.follow。
def parse(self, response):
for card in response.css("article.product_pod"):
yield {
"title": card.css("h3 a::attr(title)").get(default="").strip(),
"price": card.css("p.price_color::text").get(default="").strip(),
"url": response.urljoin(card.css("h3 a::attr(href)").get()),
}
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse)
callback 指定下一页仍由 parse 处理。不要使用固定页数死循环,也不要把页码无限加一;以页面实际存在的下一页链接为停止条件更稳。
数据重复可能来自两个层面:请求 URL 重复,或不同 URL 返回同一业务记录。前者由 Scrapy 默认指纹去重处理,后者需要使用书籍 ID、规范 URL 或其他稳定键在管道中判断。
五、导出 JSON 并做好字段清洗
完成解析后,可以直接导出 JSON Lines:
scrapy crawl books -O books.jsonl
-O 会覆盖旧文件,-o 会追加。反复测试时优先使用 -O,避免误以为爬虫抓到了重复数据。导出前还应把价格转换为数值,并处理空标题、异常编码和重复业务键。
from itemadapter import ItemAdapter
class CleanBookPipeline:
def process_item(self, item, spider):
adapter = ItemAdapter(item)
price_text = adapter.get("price", "").replace("£", "")
adapter["price"] = float(price_text)
adapter["title"] = adapter.get("title", "").strip()
return item
启用管道时,在 settings.py 的 ITEM_PIPELINES 中配置路径和优先级。字段处理规则应集中放在管道中,Spider 只负责定位页面数据。常用 Python 容器和字符串操作可以通过 Python 速查手册 随时核对。
5.1 限速、重试与合规边界
真实网站不是练习靶场。开始抓取前先看 robots.txt 和服务条款,确认数据是否允许自动访问;不要抓取登录后个人数据、绕过验证码或突破访问控制。本文示例使用公开练习站点,不代表任何页面都适合照搬。
可以在 settings.py 设置下载延迟、并发和自动限速:
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 2.0
CONCURRENT_REQUESTS_PER_DOMAIN = 2
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2.0
AUTOTHROTTLE_MAX_DELAY = 20.0
RETRY_TIMES = 2
这些值是学习项目的保守起点,不是所有网站的统一答案。遇到 429 或 503 时,应减速并等待,而不是提高并发。还要把 User-Agent、日志、失败 URL 和运行时间记录清楚,方便站点管理员联系和自己排错。
正式运行前还可以增加一个小规模验收:只抓取两页,核对记录数、必填字段、重复率和停止条件。确认输出符合预期后,再逐步增加页数。这样既能降低对站点的压力,也能在选择器变化、编码异常或翻页循环时尽早停下。Scrapy 爬虫入门阶段养成“小批验证再扩量”的习惯,比后期清理一大批错误数据更省时间。

总结
Scrapy 爬虫入门的正确顺序是先跑通最小闭环:创建项目、确认响应、解析列表、跟随下一页、导出数据。选择器放在 shell 里逐个验证,字段清洗放进管道,停止条件跟随页面真实链接。
你还要记住三点:请求去重不等于业务数据去重;导出时区分覆盖和追加;抓取速度必须服从站点规则。下一步可以为这个练习项目增加详情页请求,并为标题、价格和 URL 编写三条自动测试。
延伸学习
想把 Scrapy 爬虫继续做完整,可以按这个顺序:
- 先跟着 Python 爬虫入门实践课程 系统完成项目结构和数据处理;
- 再读 Scrapy 框架基础笔记,复习框架组件的职责;
- 最后使用 Python 代码格式化工具 统一练习项目的代码风格。
常见问题
Q:Scrapy 和 requests 应该先学哪个?
先理解 requests 更容易。requests 帮你看清一次请求与响应,Scrapy 则在其上组织调度、解析、管道和并发。简单一次性任务用 requests,持续抓取项目更适合 Scrapy。
Q:选择器在浏览器里有效,Scrapy 为什么为空?
常见原因是页面内容由 JavaScript 后续渲染,而 Scrapy 收到的原始 HTML 没有这些节点。先查看 response.text,确认数据是否实际存在,再决定寻找接口或使用允许的渲染方案。
Q:怎样限制只抓前几页?
可以读取响应中的页码,在达到上限时不再 yield 下一页请求;也可以在 Spider 中维护明确计数。不要依赖关闭程序,因为那会留下不完整输出和难以复现的状态。
Q:429 状态码应该怎么办?
立即降低频率并等待。开启 AutoThrottle、增加 DOWNLOAD_DELAY、减少域名并发,并确认网站是否允许抓取。不要用代理轮换绕过站点的访问限制。

免费 AI IDE



