admin管理员组文章数量:1130349
目录
六、Scrapy 进阶:管道高级操作
6.1 多载体存储实现
七、Scrapy 进阶:手动请求发送
7.1 实现翻页请求
思路
实现步骤
示例
7.2 Scrapy.Request 参数详解
7.3 meta 参数的使用
7.4 发送 POST 请求
方法:使用scrapy.FormRequest
示例 1:手动构造表单数据
示例 2:自动从响应中提取表单(from_response)
八、Scrapy 进阶:提高爬取效率
8.1 核心配置优化(settings.py)
示例配置:
九、Scrapy 进阶:中间件
9.1 中间件分类
9.2 下载中间件核心方法
process_request(self, request, spider)
process_response(self, request, response, spider)
process_exception(self, request, exception, spider)
9.3 中间件配置(settings.py)
9.4 中间件实现案例
案例 1:随机请求头
案例 2:随机代理 IP
案例 3:Selenium 动态加载与 Cookie 获取
十、关键配置项汇总(settings.py)
附:yield 与 return 在爬虫中的差异
一、yield 与 return 的核心差异
二、yield 在爬虫中的核心特点
三、批量爬取→批量处理(列表存储)的问题
四、yield 在爬虫中的优势
五、适用场景
六、Scrapy 进阶:管道高级操作
6.1 多载体存储实现
- 需求:将数据同时存储到 MySQL 和 Redis 等不同载体。
- 原理:一个管道类对应一种存储操作,多载体存储需定义多个管道类。
- 关键:优先级高的管道类需在process_item中return item,使 Item 传递给下一个管道类。
七、Scrapy 进阶:手动请求发送
7.1 实现翻页请求
思路
- 找到下一页 URL 地址。
- 构造 Request 对象并传递给调度器。
实现步骤
- 确定下一页 URL。
- 构造请求:scrapy.Request(url, callback)(callback指定解析函数)。
- 提交请求:yield scrapy.Request(url, callback=self.parse)。
示例
def parse(self, response):
# 提取下一页URL
next_page_url = response.xpath("//a[text()='下一页']/@href").extract_first()
if next_page_url:
# 构造并提交下一页请求
yield scrapy.Request(next_page_url, callback=self.parse)
7.2 Scrapy.Request 参数详解
scrapy.Request(url[, callback, method="GET", headers, body, cookies, meta, dont_filter=False])- callback:指定响应的解析函数。
- meta:在不同解析函数间传递数据(如meta={"item": item})。
- dont_filter:默认为 False(过滤已请求 URL),需重复请求时设为 True(如动态变化的页面)。
- method:请求方法(GET/POST)。
- headers:请求头字典(不含 Cookies)。
- cookies:Cookies 字典。
- body:POST 请求的数据(JSON 字符串)。
7.3 meta 参数的使用
- 作用:在不同解析函数间传递数据。
- 示例:
def parse(self, response):
item = MyItem()
# 提取部分数据
item['title'] = response.xpath("//h1/text()").extract_first()
# 传递item到详情页解析函数
yield scrapy.Request(detail_url, callback=self.parse_detail, meta={"item": item})
def parse_detail(self, response):
# 获取传递的item
item = response.meta["item"]
# 提取详情数据
item['content'] = response.xpath("//div[@class='content']/text()").extract_first()
yield item
注意:
meta是字典,其中
proxy键用于设置代理 IP。
7.4 发送 POST 请求
方法:使用scrapy.FormRequest
示例 1:手动构造表单数据
class GithubSpider(scrapy.Spider):
name = 'github'
start_urls = ['https://github/login']
def parse(self, response):
# 提取表单参数
authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first()
commit = response.xpath("//input[@name='commit']/@value").extract_first()
# 构造POST数据
post_data = {
'login': 'username',
'password': 'password',
'authenticity_token': authenticity_token,
'commit': commit
}
# 发送POST请求
yield scrapy.FormRequest(
'https://github/session',
formdata=post_data,
callback=self.after_login
)
def after_login(self, response):
# 登录后处理
print(response.body.decode())
示例 2:自动从响应中提取表单(from_response)
def parse(self, response):
yield scrapy.FormRequest.from_response(
response, # 自动从响应中找表单
formdata={"login": "username", "password": "password"},
callback=self.after_login
)
配置 Cookie 调试:settings.py中设置COOKIES_DEBUG = True,终端可查看 Cookie 传递过程。
八、Scrapy 进阶:提高爬取效率
8.1 核心配置优化(settings.py)
- 增加并发:CONCURRENT_REQUESTS = 100(默认 32,适当提高)。
- 降低日志级别:LOG_LEVEL = 'INFO'(减少 CPU 占用)。
- 禁止 Cookie:COOKIES_ENABLED = False(非必要时禁用)。
- 禁止重试:RETRY_ENABLED = False(减少无效请求)。
- 减少下载超时:DOWNLOAD_TIMEOUT = 10(单位:秒,快速放弃慢链接)。
示例配置:
CONCURRENT_REQUESTS = 100
LOG_LEVEL = 'ERROR'
COOKIES_ENABLED = False
RETRY_ENABLED = False
DOWNLOAD_TIMEOUT = 10
九、Scrapy 进阶:中间件
9.1 中间件分类
- 下载中间件:拦截请求 / 响应,可修改请求头、设置代理等(推荐使用)。
- 爬虫中间件:处理响应和项目数据,功能与下载中间件重复,较少使用。
- 作用:预处理 Request 和 Response 对象(如更换 Header、Cookie,使用代理 IP)。
9.2 下载中间件核心方法
process_request(self, request, spider)
- 调用时机:每个 Request 通过下载中间件时。
- 返回值:
- None:Request 继续传递给下载器或其他低权重process_request。
- Response对象:直接返回给引擎,不再请求。
- Request对象:通过引擎交给调度器,跳过其他低权重process_request。
process_response(self, request, response, spider)
- 调用时机:下载器完成请求,将响应传递给引擎时。
- 返回值:
- Response对象:传递给爬虫或其他低权重process_response。
- Request对象:通过引擎交给调度器重新请求,跳过其他低权重process_request。
process_exception(self, request, exception, spider)
- 调用时机:请求发生异常时。
- 作用:处理异常(如更换代理后重新请求)。
9.3 中间件配置(settings.py)
DOWNLOADER_MIDDLEWARES = {
'myspider.middlewares.MyDownloaderMiddleware': 543, # 键:中间件类路径;值:权重(越小越优先)
}
9.4 中间件实现案例
案例 1:随机请求头
# middlewares.py
import random
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15"
]
class RandomUserAgentMiddleware:
def process_request(self, request, spider):
request.headers['User-Agent'] = random.choice(USER_AGENTS)
return None
案例 2:随机代理 IP
# middlewares.py
import random
PROXIES = [
"https://1.71.188.37:3128",
"https://222.185.209.126:8080"
]
class ProxyMiddleware:
def process_request(self, request, spider):
proxy = random.choice(PROXIES)
request.meta['proxy'] = proxy # 设置代理
return None
def process_response(self, request, response, spider):
# 检测代理是否可用(状态码非200则更换代理)
if response.status != 200:
request.dont_filter = True # 允许重新请求
return request # 重新请求
return response
案例 3:Selenium 动态加载与 Cookie 获取
# middlewares.py
import time
from selenium import webdriver
def get_cookies():
# Selenium模拟登录获取Cookie
driver = webdriver.Chrome()
driver.get('https://github/login')
driver.find_element_by_id('login_field').send_keys('username')
driver.find_element_by_id('password').send_keys('password')
driver.find_element_by_xpath('//input[@name="commit"]').click()
time.sleep(2)
cookies = {c['name']: c['value'] for c in driver.get_cookies()}
driver.quit()
return cookies
class SeleniumMiddleware:
def process_request(self, request, spider):
cookies = get_cookies()
request.cookies = cookies # 设置Cookie
return None
十、关键配置项汇总(settings.py)
| 配置项 | 作用 | 示例 |
| BOT_NAME | 项目名称 | 'mytest' |
| SPIDER_MODULES | 爬虫模块路径 | ['mytest.spiders'] |
| NEWSPIDER_MODULE | 新爬虫模块路径 | 'mytest.spiders' |
| ROBOTSTXT_OBEY | 是否遵守 robots 协议 | True(默认) |
| USERAGENT | 用户代理标识 | 'mytest (+http://www.yourdomain)' |
| LOG_LEVEL | 日志级别 | 'WARNING'、 'ERROR' |
| LOGFILE | 日志文件路径 | './log.txt' |
| ITEM_PIPELINES | 启用管道及权重 | {'myspider.pipelines.MyPipeline': 300} |
| DOWNLOADER_MIDDLEWARES | 启用下载中间件及权重 | {'myspider.middlewares.MyMiddleware':543} |
| CONCURRENT_REQUESTS | 并发请求数 | 100 |
| COOKIES_ENABLED | 是否启用 Cookie | False(非必要时禁用) |
| RETRY_ENABLED | 是否启用重试 | False |
| DOWNLOAD_TIMEOUT | 下载超时时间(秒) | 10 |
| COOKIES_DEBUG | 调试 Cookie 传递 | True |
附:yield 与 return 在爬虫中的差异
一、yield 与 return 的核心差异
- return:结束函数执行,销毁函数状态,一次性返回结果。
- yield:暂停函数执行,保留函数状态,可多次返回中间结果,用于生成器函数。
二、yield 在爬虫中的核心特点
- 边爬边出:实现流式处理,爬取一条数据就返回一条,立即被处理(如保存),再继续爬取下一条。
- 内存占用恒定:每次只返回一个数据,不会因数据量过大而占用大量内存,适合 10 万级以上大量数据的爬取。
- 正确使用:需配合实时处理流程,若先一次性爬完所有数据再逐个 yield,则会增加不必要的状态管理开销,属于误用。
三、批量爬取→批量处理(列表存储)的问题
- 内存占用过高:所有数据同时存放在内存中,数据量较大时(如百万级),可能占用数 GB 内存,触发内存交换,导致程序运行速度急剧下降,甚至因内存溢出被系统终止。
- 处理延迟,安全性差:必须等所有数据爬取完成后才开始处理,数据长期处于闲置状态,无法被后续流程实时使用。且中途若爬虫意外崩溃(如网络中断、程序报错),已爬取的数据会全部丢失,需重新爬取。
- 资源利用效率低:爬取和处理环节完全串行,总耗时更长。例如爬取 1000 条数据耗时 10 分钟,保存耗时 2 分钟,总耗时 12 分钟。
- 易触发反爬机制:可能为快速填满列表而在短时间内集中发送大量请求,对目标网站压力集中,容易触发 IP 封禁、验证码等反爬措施。
四、yield 在爬虫中的优势
- 内存优化:避免大量数据堆积在内存中,减少内存操作开销,使爬虫更稳定。
- 提升整体效率:支持爬取与处理并行工作,缩短总耗时。如爬取 10 分钟 + 保存 2 分钟,总耗时接近 10 分钟。
- 降低反爬风险:可在 yield 前后自然加入延迟(如time.sleep(1)),分散请求压力,降低被目标网站反爬的概率。
- 数据实时处理:数据爬取后能立即被处理,满足实时分析、展示等需求。
五、适用场景
- yield:适合中大规模数据爬取,能高效、稳定地处理大量数据,尤其适合需要长期稳定运行的程序。
- 批量爬取→批量处理:仅适合极小数据量(如几十条)的场景,简单直观但扩展性差。
目录
六、Scrapy 进阶:管道高级操作
6.1 多载体存储实现
七、Scrapy 进阶:手动请求发送
7.1 实现翻页请求
思路
实现步骤
示例
7.2 Scrapy.Request 参数详解
7.3 meta 参数的使用
7.4 发送 POST 请求
方法:使用scrapy.FormRequest
示例 1:手动构造表单数据
示例 2:自动从响应中提取表单(from_response)
八、Scrapy 进阶:提高爬取效率
8.1 核心配置优化(settings.py)
示例配置:
九、Scrapy 进阶:中间件
9.1 中间件分类
9.2 下载中间件核心方法
process_request(self, request, spider)
process_response(self, request, response, spider)
process_exception(self, request, exception, spider)
9.3 中间件配置(settings.py)
9.4 中间件实现案例
案例 1:随机请求头
案例 2:随机代理 IP
案例 3:Selenium 动态加载与 Cookie 获取
十、关键配置项汇总(settings.py)
附:yield 与 return 在爬虫中的差异
一、yield 与 return 的核心差异
二、yield 在爬虫中的核心特点
三、批量爬取→批量处理(列表存储)的问题
四、yield 在爬虫中的优势
五、适用场景
六、Scrapy 进阶:管道高级操作
6.1 多载体存储实现
- 需求:将数据同时存储到 MySQL 和 Redis 等不同载体。
- 原理:一个管道类对应一种存储操作,多载体存储需定义多个管道类。
- 关键:优先级高的管道类需在process_item中return item,使 Item 传递给下一个管道类。
七、Scrapy 进阶:手动请求发送
7.1 实现翻页请求
思路
- 找到下一页 URL 地址。
- 构造 Request 对象并传递给调度器。
实现步骤
- 确定下一页 URL。
- 构造请求:scrapy.Request(url, callback)(callback指定解析函数)。
- 提交请求:yield scrapy.Request(url, callback=self.parse)。
示例
def parse(self, response):
# 提取下一页URL
next_page_url = response.xpath("//a[text()='下一页']/@href").extract_first()
if next_page_url:
# 构造并提交下一页请求
yield scrapy.Request(next_page_url, callback=self.parse)
7.2 Scrapy.Request 参数详解
scrapy.Request(url[, callback, method="GET", headers, body, cookies, meta, dont_filter=False])- callback:指定响应的解析函数。
- meta:在不同解析函数间传递数据(如meta={"item": item})。
- dont_filter:默认为 False(过滤已请求 URL),需重复请求时设为 True(如动态变化的页面)。
- method:请求方法(GET/POST)。
- headers:请求头字典(不含 Cookies)。
- cookies:Cookies 字典。
- body:POST 请求的数据(JSON 字符串)。
7.3 meta 参数的使用
- 作用:在不同解析函数间传递数据。
- 示例:
def parse(self, response):
item = MyItem()
# 提取部分数据
item['title'] = response.xpath("//h1/text()").extract_first()
# 传递item到详情页解析函数
yield scrapy.Request(detail_url, callback=self.parse_detail, meta={"item": item})
def parse_detail(self, response):
# 获取传递的item
item = response.meta["item"]
# 提取详情数据
item['content'] = response.xpath("//div[@class='content']/text()").extract_first()
yield item
注意:
meta是字典,其中
proxy键用于设置代理 IP。
7.4 发送 POST 请求
方法:使用scrapy.FormRequest
示例 1:手动构造表单数据
class GithubSpider(scrapy.Spider):
name = 'github'
start_urls = ['https://github/login']
def parse(self, response):
# 提取表单参数
authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first()
commit = response.xpath("//input[@name='commit']/@value").extract_first()
# 构造POST数据
post_data = {
'login': 'username',
'password': 'password',
'authenticity_token': authenticity_token,
'commit': commit
}
# 发送POST请求
yield scrapy.FormRequest(
'https://github/session',
formdata=post_data,
callback=self.after_login
)
def after_login(self, response):
# 登录后处理
print(response.body.decode())
示例 2:自动从响应中提取表单(from_response)
def parse(self, response):
yield scrapy.FormRequest.from_response(
response, # 自动从响应中找表单
formdata={"login": "username", "password": "password"},
callback=self.after_login
)
配置 Cookie 调试:settings.py中设置COOKIES_DEBUG = True,终端可查看 Cookie 传递过程。
八、Scrapy 进阶:提高爬取效率
8.1 核心配置优化(settings.py)
- 增加并发:CONCURRENT_REQUESTS = 100(默认 32,适当提高)。
- 降低日志级别:LOG_LEVEL = 'INFO'(减少 CPU 占用)。
- 禁止 Cookie:COOKIES_ENABLED = False(非必要时禁用)。
- 禁止重试:RETRY_ENABLED = False(减少无效请求)。
- 减少下载超时:DOWNLOAD_TIMEOUT = 10(单位:秒,快速放弃慢链接)。
示例配置:
CONCURRENT_REQUESTS = 100
LOG_LEVEL = 'ERROR'
COOKIES_ENABLED = False
RETRY_ENABLED = False
DOWNLOAD_TIMEOUT = 10
九、Scrapy 进阶:中间件
9.1 中间件分类
- 下载中间件:拦截请求 / 响应,可修改请求头、设置代理等(推荐使用)。
- 爬虫中间件:处理响应和项目数据,功能与下载中间件重复,较少使用。
- 作用:预处理 Request 和 Response 对象(如更换 Header、Cookie,使用代理 IP)。
9.2 下载中间件核心方法
process_request(self, request, spider)
- 调用时机:每个 Request 通过下载中间件时。
- 返回值:
- None:Request 继续传递给下载器或其他低权重process_request。
- Response对象:直接返回给引擎,不再请求。
- Request对象:通过引擎交给调度器,跳过其他低权重process_request。
process_response(self, request, response, spider)
- 调用时机:下载器完成请求,将响应传递给引擎时。
- 返回值:
- Response对象:传递给爬虫或其他低权重process_response。
- Request对象:通过引擎交给调度器重新请求,跳过其他低权重process_request。
process_exception(self, request, exception, spider)
- 调用时机:请求发生异常时。
- 作用:处理异常(如更换代理后重新请求)。
9.3 中间件配置(settings.py)
DOWNLOADER_MIDDLEWARES = {
'myspider.middlewares.MyDownloaderMiddleware': 543, # 键:中间件类路径;值:权重(越小越优先)
}
9.4 中间件实现案例
案例 1:随机请求头
# middlewares.py
import random
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15"
]
class RandomUserAgentMiddleware:
def process_request(self, request, spider):
request.headers['User-Agent'] = random.choice(USER_AGENTS)
return None
案例 2:随机代理 IP
# middlewares.py
import random
PROXIES = [
"https://1.71.188.37:3128",
"https://222.185.209.126:8080"
]
class ProxyMiddleware:
def process_request(self, request, spider):
proxy = random.choice(PROXIES)
request.meta['proxy'] = proxy # 设置代理
return None
def process_response(self, request, response, spider):
# 检测代理是否可用(状态码非200则更换代理)
if response.status != 200:
request.dont_filter = True # 允许重新请求
return request # 重新请求
return response
案例 3:Selenium 动态加载与 Cookie 获取
# middlewares.py
import time
from selenium import webdriver
def get_cookies():
# Selenium模拟登录获取Cookie
driver = webdriver.Chrome()
driver.get('https://github/login')
driver.find_element_by_id('login_field').send_keys('username')
driver.find_element_by_id('password').send_keys('password')
driver.find_element_by_xpath('//input[@name="commit"]').click()
time.sleep(2)
cookies = {c['name']: c['value'] for c in driver.get_cookies()}
driver.quit()
return cookies
class SeleniumMiddleware:
def process_request(self, request, spider):
cookies = get_cookies()
request.cookies = cookies # 设置Cookie
return None
十、关键配置项汇总(settings.py)
| 配置项 | 作用 | 示例 |
| BOT_NAME | 项目名称 | 'mytest' |
| SPIDER_MODULES | 爬虫模块路径 | ['mytest.spiders'] |
| NEWSPIDER_MODULE | 新爬虫模块路径 | 'mytest.spiders' |
| ROBOTSTXT_OBEY | 是否遵守 robots 协议 | True(默认) |
| USERAGENT | 用户代理标识 | 'mytest (+http://www.yourdomain)' |
| LOG_LEVEL | 日志级别 | 'WARNING'、 'ERROR' |
| LOGFILE | 日志文件路径 | './log.txt' |
| ITEM_PIPELINES | 启用管道及权重 | {'myspider.pipelines.MyPipeline': 300} |
| DOWNLOADER_MIDDLEWARES | 启用下载中间件及权重 | {'myspider.middlewares.MyMiddleware':543} |
| CONCURRENT_REQUESTS | 并发请求数 | 100 |
| COOKIES_ENABLED | 是否启用 Cookie | False(非必要时禁用) |
| RETRY_ENABLED | 是否启用重试 | False |
| DOWNLOAD_TIMEOUT | 下载超时时间(秒) | 10 |
| COOKIES_DEBUG | 调试 Cookie 传递 | True |
附:yield 与 return 在爬虫中的差异
一、yield 与 return 的核心差异
- return:结束函数执行,销毁函数状态,一次性返回结果。
- yield:暂停函数执行,保留函数状态,可多次返回中间结果,用于生成器函数。
二、yield 在爬虫中的核心特点
- 边爬边出:实现流式处理,爬取一条数据就返回一条,立即被处理(如保存),再继续爬取下一条。
- 内存占用恒定:每次只返回一个数据,不会因数据量过大而占用大量内存,适合 10 万级以上大量数据的爬取。
- 正确使用:需配合实时处理流程,若先一次性爬完所有数据再逐个 yield,则会增加不必要的状态管理开销,属于误用。
三、批量爬取→批量处理(列表存储)的问题
- 内存占用过高:所有数据同时存放在内存中,数据量较大时(如百万级),可能占用数 GB 内存,触发内存交换,导致程序运行速度急剧下降,甚至因内存溢出被系统终止。
- 处理延迟,安全性差:必须等所有数据爬取完成后才开始处理,数据长期处于闲置状态,无法被后续流程实时使用。且中途若爬虫意外崩溃(如网络中断、程序报错),已爬取的数据会全部丢失,需重新爬取。
- 资源利用效率低:爬取和处理环节完全串行,总耗时更长。例如爬取 1000 条数据耗时 10 分钟,保存耗时 2 分钟,总耗时 12 分钟。
- 易触发反爬机制:可能为快速填满列表而在短时间内集中发送大量请求,对目标网站压力集中,容易触发 IP 封禁、验证码等反爬措施。
四、yield 在爬虫中的优势
- 内存优化:避免大量数据堆积在内存中,减少内存操作开销,使爬虫更稳定。
- 提升整体效率:支持爬取与处理并行工作,缩短总耗时。如爬取 10 分钟 + 保存 2 分钟,总耗时接近 10 分钟。
- 降低反爬风险:可在 yield 前后自然加入延迟(如time.sleep(1)),分散请求压力,降低被目标网站反爬的概率。
- 数据实时处理:数据爬取后能立即被处理,满足实时分析、展示等需求。
五、适用场景
- yield:适合中大规模数据爬取,能高效、稳定地处理大量数据,尤其适合需要长期稳定运行的程序。
- 批量爬取→批量处理:仅适合极小数据量(如几十条)的场景,简单直观但扩展性差。
版权声明:本文标题:Scrapy框架入门和进阶(下篇) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://it.en369.cn/jiaocheng/1759990874a2836924.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论