【0基础学爬虫】爬虫基础之scrapy的使用
字数 1799 2025-08-20 18:18:23
Scrapy爬虫框架全面教学文档
一、Scrapy简介
Scrapy是一个用于爬取网站并提取结构化数据的强大且灵活的开源框架。它具有以下特点:
- 提供简单易用的工具和组件
- 支持定义爬虫、调度请求、处理响应并存储提取的数据
- 具有高效的异步处理能力
- 支持分布式爬取
- 通过中间件和扩展机制可以方便地定制和扩展功能
- 广泛应用于数据挖掘、信息聚合和自动化测试等领域
二、Scrapy工作流程
- 启动爬虫:Scrapy启动并激活爬虫,从初始URL开始爬取
- 调度请求:爬虫生成初始请求,并将其发送给调度器
- 下载页面:调度器将请求发送给下载器,下载器从互联网获取页面
- 处理响应:下载器将响应返回给引擎,传递给爬虫
- 提取数据:爬虫从响应中提取数据(items)和更多的URL(新的请求)
- 处理数据:提取的数据通过项目管道进行处理,清洗并存储
- 继续爬取:新的请求被调度器处理,继续下载和提取数据,直到所有请求处理完毕
三、Scrapy安装与项目创建
1. 安装Scrapy
pip install scrapy
2. 创建新项目
scrapy startproject scrapy_demo
3. 创建爬虫模板
cd scrapy_demo
scrapy genspider example example.com
4. 项目结构说明
scrapy_demo/
├── spiders/ # 存放爬虫文件
├── items.py # 定义爬取的数据结构
├── middlewares.py # 定义下载中间件和爬虫中间件
├── pipelines.py # 定义管道,用于处理爬虫提取的数据
├── settings.py # 项目的基本配置
四、Scrapy基本使用
1. 编写基础爬虫
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example"
start_urls = ["https://movie.douban.com/top250"]
def parse(self, response):
print(response.text)
2. 运行爬虫
scrapy crawl example
3. 解决403问题和robots协议
在settings.py中修改:
# 不遵守robots协议
ROBOTSTXT_OBEY = False
# 设置默认请求头
DEFAULT_REQUEST_HEADERS = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}
4. 两种运行方式
- 终端运行:
scrapy crawl example
- Python脚本运行:
from scrapy import cmdline
if __name__ == '__main__':
cmdline.execute("scrapy crawl example".split())
# 不输出提示信息
# cmdline.execute("scrapy crawl example --nolog".split())
五、数据提取与翻页
1. 数据提取示例
def parse(self, response):
ol_list = response.xpath('//ol[@class="grid_view"]/li')
for ol in ol_list:
item = {}
item['title'] = ol.xpath('.//div[@class="hd"]/a/span[1]/text()').extract_first()
item['rating'] = ol.xpath('.//div[@class="bd"]/div/span[2]/text()').extract_first()
item['quote'] = ol.xpath('.//div[@class="bd"]//p[@class="quote"]/span/text()').extract_first()
print(item)
2. 翻页处理两种方式
方式一:使用callback回调
def parse(self, response):
# ...数据提取代码...
if response.xpath("//a[text()='后页>']/@href").extract_first() is not None:
next_url = response.urljoin(response.xpath("//a[text()='后页>']/@href").extract_first())
yield scrapy.Request(url=next_url, callback=self.parse)
方式二:重写start_requests方法
def start_requests(self):
for i in range(0, 5):
url = 'https://movie.douban.com/top250?start={}&filter='.format(i * 25)
yield scrapy.Request(url)
六、Scrapy Item使用
1. 定义Item
import scrapy
class ScrapyDemoItem(scrapy.Item):
title = scrapy.Field()
rating = scrapy.Field()
quote = scrapy.Field()
2. 使用Item
from scrapy_demo.items import ScrapyDemoItem
def parse(self, response):
ol_list = response.xpath('//ol[@class="grid_view"]/li')
for ol in ol_list:
item = ScrapyDemoItem()
item['title'] = ol.xpath('.//div[@class="hd"]/a/span[1]/text()').extract_first()
item['rating'] = ol.xpath('.//div[@class="bd"]/div/span[2]/text()').extract_first()
item['quote'] = ol.xpath('.//div[@class="bd"]//p[@class="quote"]/span/text()').extract_first()
yield item
七、数据存储Pipeline
1. MySQL存储示例
import pymysql
from itemadapter import ItemAdapter
class MysqlPipeline:
def __init__(self):
self.connection = pymysql.connect(
user='root',
password='root',
db='scrapy_demo',
)
self.cursor = self.connection.cursor()
self.create_table()
def create_table(self):
table = """
CREATE TABLE IF NOT EXISTS douban (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
rating FLOAT NOT NULL,
quote TEXT
)CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
"""
self.cursor.execute(table)
self.connection.commit()
def process_item(self, item, spider):
try:
self.cursor.execute("INSERT INTO douban(id,title, rating, quote) VALUES (%s,%s, %s, %s)",
(0, item['title'], item['rating'], item['quote']))
self.connection.commit()
except pymysql.MySQLError as e:
spider.logger.error(f"Error saving item: {e}")
print(e)
return item
def close_spider(self, spider):
self.cursor.close()
self.connection.close()
2. 启用Pipeline
在settings.py中:
ITEM_PIPELINES = {
"scrapy_demo.pipelines.MysqlPipeline": 300,
}
八、Scrapy中间件
1. 下载中间件基础
from feapder.network import user_agent
class ScrapyDemoDownloaderMiddleware:
def process_request(self, request, spider):
request.headers['User-Agent'] = user_agent.get()
return None
2. 设置代理
def process_request(self, request, spider):
request.headers['User-Agent'] = user_agent.get()
request.meta['proxy'] = "http://127.0.0.1:7890"
return None
3. 中间件权重
在settings.py中:
DOWNLOADER_MIDDLEWARES = {
"scrapy_demo.middlewares.OneMiddleware": 543,
"scrapy_demo.middlewares.TwoMiddleware": 544
}
九、Scrapy-Redis分布式爬虫
1. 安装
pip install scrapy-redis
注意:Scrapy版本需要替换成2.9.0版本或者2.0.0以下
2. 配置
在settings.py中:
# 设置Redis主机和端口
REDIS_URL = 'redis://127.0.0.1:6379/0'
# 使用Scrapy-Redis的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 使用Scrapy-Redis的去重器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 开启redis管道
ITEM_PIPELINES = {
"scrapy_redis.pipelines.RedisPipeline": 301
}
3. 编写Redis爬虫
from scrapy_redis.spiders import RedisSpider
class RedisDemoSpider(RedisSpider):
name = "redis_demo"
redis_key = "redis_demo:start_urls" # redis key
def parse(self, response):
ol_list = response.xpath('//ol[@class="grid_view"]/li')
for ol in ol_list:
item = {}
item['title'] = ol.xpath('.//div[@class="hd"]/a/span[1]/text()').extract_first()
item['rating'] = ol.xpath('.//div[@class="bd"]/div/span[2]/text()').extract_first()
item['quote'] = ol.xpath('.//div[@class="bd"]//p[@class="quote"]/span/text()').extract_first()
print(item)
yield item
4. 添加URL到Redis队列
import redis
r = redis.Redis(db=0)
r.lpush('redis_demo:start_urls', "https://movie.douban.com/top250")
5. 持久化存储
在settings.py中:
SCHEDULER_PERSIST = True # 持久化爬取状态
6. 分布式配置
在settings.py中修改Redis连接:
REDIS_URL = '远程电脑ip地址'
十、关键对象说明
1. Request对象参数
| 参数 | 描述 |
|---|---|
| url | 请求的URL |
| callback | 用于处理该请求的回调函数,默认是parse方法 |
| method | HTTP请求方法,如'GET','POST'等,默认为'GET' |
| headers | 请求头信息 |
| body | 请求体,通常在POST请求中使用 |
| cookies | 请求携带的Cookies |
| meta | 该请求的元数据字典,用于在不同请求之间传递数据 |
| encoding | 请求的编码格式,默认为'utf-8' |
| priority | 请求的优先级,默认值为0 |
2. Response对象参数
| 参数 | 描述 |
|---|---|
| url | 响应的URL |
| status | HTTP响应状态码 |
| headers | 响应头信息 |
| body | 响应体内容,二进制格式 |
| flags | 响应的标志列表 |
| request | 生成此响应的请求对象 |
| meta | 该请求的元数据字典 |
| encoding | 响应的编码格式 |
| text | 响应体内容,解码为字符串格式 |
| css | CSS选择器 |
| xpath | XPath选择器 |
| json | 解析JSON响应体并返回字典或列表 |
十一、最佳实践建议
- 遵守robots协议:除非必要,否则应遵守目标网站的robots.txt规则
- 设置合理的请求间隔:避免对目标网站造成过大压力
- 处理异常情况:网络错误、页面解析失败等情况应有相应处理
- 日志记录:记录爬取过程中的关键信息,便于排查问题
- 数据去重:使用Scrapy-Redis或其他方式实现数据去重
- 分布式部署:对于大规模爬取任务,考虑使用分布式架构
- 遵守法律法规:确保爬取行为符合相关法律法规和网站使用条款