Scrapy 是 Python 最强大的开源网络爬虫框架之一,专为高效、结构化数据抓取设计。它基于 Twisted 异步网络库,支持高并发爬取,并提供了完整的爬虫生命周期管理。
官方文档: Scrapy Documentation
1. Scrapy 核心架构
Scrapy 的架构清晰分层,各组件协同工作:
组件 | 作用 |
---|---|
Engine | 调度全局请求与数据流 |
Scheduler | 管理待爬取的请求队列 |
Downloader | 发送 HTTP 请求,获取响应 |
Spiders | 解析响应,提取数据或生成新请求 |
Item Pipeline | 处理清洗、验证、存储数据 |
Downloader Middlewares | 处理请求/响应(如代理、UA 伪装) |
Spider Middlewares | 处理 Spider 输入/输出 |
2. 安装与环境配置
pip install scrapy
验证安装:
scrapy version # 输出版本,如 Scrapy 2.11.0
3. 创建 Scrapy 项目
快速生成项目骨架:
scrapy startproject myproject
cd myproject
scrapy genspider example example.com
生成的文件结构:
myproject/
├── scrapy.cfg
└── myproject/
├── items.py # 定义数据结构
├── middlewares.py # 中间件配置
├── pipelines.py # 数据处理管道
├── settings.py # 全局设置(如并发数、延迟)
└── spiders/ # 爬虫代码目录
└── example.py
4. 编写 Spider 核心逻辑
修改 spiders/example.py
,定义爬取规则与数据解析:
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example" # 爬虫唯一标识
allowed_domains = ["example.com"] # 允许爬取的域名
start_urls = ["https://example.com"] # 起始 URL
def parse(self, response):
# 解析响应内容
title = response.css('h1::text').get()
yield {'title': title} # 生成 Item 或 Request
# 跟踪分页链接示例
next_page = response.css('a.next-page::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)
5. 定义数据结构(Item)
在 items.py
中定义结构化数据:
import scrapy
class BookItem(scrapy.Item):
title = scrapy.Field()
price = scrapy.Field()
description = scrapy.Field()
6. 数据存储(Item Pipeline)
在 pipelines.py
中处理数据存储:
class JsonWriterPipeline:
def open_spider(self, spider):
self.file = open('books.json', 'w', encoding='utf-8')
def close_spider(self, spider):
self.file.close()
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
在 settings.py
中启用 Pipeline:
ITEM_PIPELINES = {
'myproject.pipelines.JsonWriterPipeline': 300,
}
7. 中间件高级应用
示例:随机 User-Agent 和代理
修改 middlewares.py
:
from scrapy import signals
import random
class RandomUserAgentMiddleware:
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...'
]
def process_request(self, request, spider):
request.headers['User-Agent'] = random.choice(self.user_agents)
class ProxyMiddleware:
def process_request(self, request, spider):
request.meta['proxy'] = 'http://proxy_ip:port'
在 settings.py
中激活中间件:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.RandomUserAgentMiddleware': 543,
'myproject.middlewares.ProxyMiddleware': 544,
}
8. 配置调优(settings.py)
关键参数设置:
CONCURRENT_REQUESTS = 16 # 并发请求数
DOWNLOAD_DELAY = 1 # 请求延迟(秒)
AUTOTHROTTLE_ENABLED = True # 自动限速
DEPTH_LIMIT = 3 # 最大爬取深度
COOKIES_ENABLED = False # 禁用 Cookies(减少指纹)
FEED_EXPORT_ENCODING = 'utf-8' # 导出文件编码
9. 运行与调试
启动爬虫:
scrapy crawl example -o output.json
Shell 调试:
scrapy shell 'https://example.com' >>> response.css('h1::text').get()
10. 应对动态内容(如 JavaScript 渲染)
使用 Splash 或 Scrapy-Selenium 处理动态页面:
# 示例:集成 Splash
class JSSpider(scrapy.Spider):
def start_requests(self):
yield scrapy.Request(
url='http://example.com',
meta={'splash': {'args': {'wait': 2.5}}}, # 等待 JS 执行
callback=self.parse
)
11. 分布式爬虫(Scrapy-Redis)
扩展 Scrapy 实现分布式爬取:
安装扩展:
pip install scrapy-redis
修改
settings.py
:SCHEDULER = "scrapy_redis.scheduler.Scheduler" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" REDIS_URL = 'redis://user:pass@host:port'
12. 反爬策略与道德规范
遵守 robots.txt:在
settings.py
中设置:ROBOTSTXT_OBEY = True
- 限速与请求头伪装:如设置
DOWNLOAD_DELAY
和随机 User-Agent - 验证码处理:使用第三方服务(如 2Captcha)或手动介入
实战案例:爬取图书信息
# spiders/book_spider.py
class BookSpider(scrapy.Spider):
name = "books"
start_urls = ['http://books.toscrape.com']
def parse(self, response):
for book in response.css('article.product_pod'):
item = BookItem()
item['title'] = book.css('h3 a::attr(title)').get()
item['price'] = book.css('p.price_color::text').get()
yield item
next_page = response.css('li.next a::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)
评论 (0)