文章目录
你见过凌晨四点的网页源码吗?别怕,Scrapy就是你的咖啡因☕!
为啥是Scrapy?—— 不是所有爬虫都叫这个名字!
(先唠点实在的)想从网上薅点数据?写个小脚本也能凑合对吧?但当你面对:
- 几百页翻页翻到怀疑人生 😫
- AJAX加载搞得一头雾水
- 网站反爬让你频繁“喜提”IP封禁
- 数据清洗写到手抽筋…
这时候,Scrapy 就该登场了!这可不是普通的爬虫库,它是一个完整的、企业级的爬虫框架!!!(划重点)它把爬取流程给你拆解得明明白白,就像搭乐高一样清晰!省心程度直接飙升200%!
🔧 Scrapy的核心秘密武器:架构就是王道!
别被“框架”吓到!理解它的结构,用起来才丝滑:
- 引擎 (Engine): 大佬指挥官!调度所有组件协作。
- 调度器 (Scheduler): 排队小能手!管理待抓取的URL队列。
- 下载器 (Downloader): 网络冲浪🏄♂️高手!负责发出HTTP请求,拿回网页内容。
- 爬虫 (Spiders): 你的主战场! 你在这里定义:
start_urls
: 从哪几个链接开始爬?parse
: 拿到网页后怎么处理?怎么抽数据?下一页怎么找?(核心逻辑在这!)
- 项目管道 (Item Pipeline): 数据处理的流水线!清洗、验证、存数据库…都在这里搞定。
- 中间件 (Middleware): 高级玩家的魔法棒! 全局干预请求和响应:
- 加代理?伪装User-Agent?处理Cookie?都在下载器中间件!
- 处理爬虫输出?在爬虫中间件!
(超级重要) 请求(Request) => 引擎 => 调度器 => 下载器 => 响应(Response) => 引擎 => 爬虫(parse
) => 引擎 => 管道。记住这个流程,写代码不迷路!
⚡️ 实战!手把手撸一个豆瓣读书爬虫
假设我们想抓取豆瓣读书某个标签下的书名、作者、评分(纯技术演示,遵守 robots.txt 哦!)。
Step 1: 一键安装(简单到哭)
pip install scrapy
Step 2: 创建你的第一个“虫子”(项目)
scrapy startproject douban_book_spider
cd douban_book_spider
Step 3: 下个“蛋”(创建爬虫文件)
scrapy genspider book_spider book.douban.com
# 会在 spiders/ 下生成 book_spider.py
Step 4: 编写你的“虫子”逻辑 (spiders/book_spider.py
)
import scrapy
from douban_book_spider.items import DoubanBookItem # 稍后定义Item
class BookSpiderSpider(scrapy.Spider):
name = 'book_spider' # 虫子名字,唯一标识
allowed_domains = ['book.douban.com'] # 限定爬取范围
start_urls = ['https://book.douban.com/tag/小说?start=0&type=T'] # 起始页(小说标签第一页)
def parse(self, response):
# 神器来了!用CSS选择器定位每本书的区块
book_list = response.css('ul.subject-list > li.subject-item')
# 遍历每一本书
for book in book_list:
# 创建 Item 对象,用来装结构化数据
item = DoubanBookItem()
# CSS选择器抽取书名 (注意::text和get()/getall()用法)
item['title'] = book.css('h2 a::attr(title)').get().strip() # 拿title属性
# 抽取作者/出版社信息,可能有多行,处理一下
pub_info = book.css('.pub::text').get().strip()
item['author'] = pub_info.split('/')[0].strip() if pub_info else None
# 抽取评分(可能没有评分)
rating_str = book.css('.rating_nums::text').get()
item['rating'] = float(rating_str.strip()) if rating_str else 0.0
# 把装好数据的item "yield" 出去,交给引擎->管道处理
yield item
# 翻页!找“后页”的链接
next_page_url = response.css('span.next a::attr(href)').get()
if next_page_url:
# 构建绝对URL(相对链接变绝对链接)
next_page_absolute_url = response.urljoin(next_page_url)
# 告诉调度器:去爬下一页!回调函数还是parse自己
yield scrapy.Request(url=next_page_absolute_url, callback=self.parse)
Step 5: 定义你的“数据容器”——Item (items.py
)
import scrapy
class DoubanBookItem(scrapy.Item):
# 定义好我们要爬取的字段,像数据库表结构
title = scrapy.Field() # 书名
author = scrapy.Field() # 作者
rating = scrapy.Field() # 评分
# 还可以加更多,比如出版日期、ISBN等
Step 6: 配置你的流水线(可选但常用)(pipelines.py
)
假设我们想把数据存到JSON文件:
import json
class JsonWriterPipeline:
def open_spider(self, spider):
# 爬虫启动时打开文件
self.file = open('douban_books.json', 'w', encoding='utf-8')
self.file.write('[\n') # 写JSON数组的开头
def close_spider(self, spider):
# 爬虫结束时关闭文件
self.file.write('\n]')
self.file.close()
def process_item(self, item, spider):
# 处理每个item,转换成JSON行
line = json.dumps(dict(item), ensure_ascii=False) + ",\n"
self.file.write(line)
return item # 重要!继续传递给后面的管道(如果有)
别忘激活管道! 在 settings.py
里取消注释并修改:
ITEM_PIPELINES = {
'douban_book_spider.pipelines.JsonWriterPipeline': 300, # 数字越小优先级越高
}
Step 7: 释放你的“虫子”!运行爬虫!
scrapy crawl book_spider -O douban_books.json # -O 覆盖输出,-o 追加输出 (Scrapy 2.0+)
# 或者用上面配置的管道,就不用 -O 了
搞定! 坐等 douban_books.json
文件里出现你想要的书目数据吧!(注意频率,别把人家服务器搞崩了!)
🛡️ 江湖险恶!新手避坑指南(血泪经验)
-
反爬是常态,心态要摆正!
- User-Agent伪装:在
settings.py
里设置USER_AGENT
,别用默认的Scrapy/...
!找个浏览器的UA。 - 请求头Headers:模仿浏览器!在
start_requests
或下载器中间件里加Referer
,Cookie
(谨慎用)。 - 延迟下载 DOWNLOAD_DELAY:
settings.py
里设置,比如DOWNLOAD_DELAY = 2
(2秒请求一次)。(超级重要) 做个有道德的爬虫! - IP代理:被封IP太常见了!用
scrapy-rotating-proxies
等中间件轮换代理池。免费代理不稳,量力而行。 - 验证码:硬骨头!简单图形验证码可尝试OCR库(如
ddddocr
),复杂验证码考虑打码平台(成本高)或绕路(如模拟登录拿Cookie)。
- User-Agent伪装:在
-
XPath/CSS选择器不灵了?
- AJAX动态加载:爬不到数据?看Network面板找真正的数据接口(通常是XHR请求)。用
scrapy.Request
或scrapy.FormRequest
模拟请求接口!神器scrapy-splash
或scrapy-playwright
可以渲染JS。 - 结构复杂:善用浏览器开发者工具的
Copy XPath
/Copy selector
(仅作参考!经常需要调整)。多写response.xpath('...').get()
测试。
- AJAX动态加载:爬不到数据?看Network面板找真正的数据接口(通常是XHR请求)。用
-
Item Pipeline 妙用无穷!
- 数据清洗:在管道里去掉空白、转换格式(字符串转数字/日期)、处理缺失值。
- 数据去重:自己写逻辑或者用
scrapy.dupefilters
。 - 多种存储:除了JSON,可以轻松存到MySQL (
pymysql
), MongoDB (pymongo
), CSV (csv
模块)等。管道分开写,激活多个!
-
日志和调试是你的好朋友!
- 在爬虫里用
self.logger.info('信息')
/self.logger.debug('调试')
。 - 用
scrapy shell <url>
快速测试你的选择器!(强烈推荐!效率翻倍) - 查看
settings.py
里的LOG_LEVEL
(默认DEBUG,信息太多可设为INFO/WARNING)。
- 在爬虫里用
💡 进阶!让你的Scrapy飞起来!
- CrawlSpider & Rules:处理规则清晰的网站(如新闻站、博客),自动跟进符合规则的链接,比写
parse
翻页省力多了! - Item Loaders:更强大、更灵活的数据提取和预处理方式,内置处理器(处理输入、输出、连接等)。
- Feed Exports:用
settings.py
配置直接输出多种格式(JSON, CSV, XML)到文件/FTP/S3,不用自己写管道。 - 中间件深度定制:
- 下载器中间件:处理代理、User-Agent轮换、请求重试、自定义错误处理。
- 爬虫中间件:处理爬虫输入(请求)和输出(Item/Request)。
- ScrapyRT:把Scrapy爬虫变成HTTP服务,通过API触发爬取。
- Scrapy Cluster / Scrapyd:分布式部署和管理爬虫,处理大规模抓取。
🌟 写在最后:爬虫有度,心中有秤!
Scrapy给了你强大的武器,但务必记得:
- 尊重
robots.txt
:网站的“交通规则”,看它允不允许你爬、爬多快。 - 控制频率:疯狂请求等于DoS攻击!设置合理的
DOWNLOAD_DELAY
和并发数 (CONCURRENT_REQUESTS
)。 - 辨别数据性质:爬公开信息OK,爬用户隐私、付费内容?快停下!法律风险极高!
- 标明数据来源:如果后续使用或发布爬取的数据,注明来源是基本的尊重。
掌握了Scrapy,你就如同拥有了在网络信息迷雾中精准导航的罗盘🧭。它不仅仅是工具,更是一种结构化解决问题的思维。从简单列表页开始,逐步挑战更复杂的站点和反爬机制,那种成功抓取到数据的成就感,真的会上瘾!(合理合法的那种!)快去释放你的数据侦探之魂吧!🕵️♂️💻