yield关键字
yield
关键字扮演着核心角色,主要用于处理异步数据流和请求调度。
主要作用
-
生成器函数:将方法转换为生成器,可以逐步产生结果而不需要一次性返回所有数据
-
异步处理:支持Scrapy的异步架构,提高爬取效率
-
请求调度:用于发起新的请求或传递处理后的数据
使用场景
使用场景 | 代码示例 | 说明 |
---|---|---|
发起新请求 | yield scrapy.Request(url, callback=self.parse_detail) | 用于生成新的请求,Scrapy 会自动调度并下载,完成后调用指定的回调函数。 |
返回提取的数据 | yield {"title": response.css("h1::text").get()} | 返回字典或 Item 对象,数据会进入 Item Pipeline 进行处理和存储。 |
处理分页 | yield response.follow(next_page, callback=self.parse) | 跟踪下一页链接,常用于分页爬取。 |
多个结果逐条返回 | python<br>for product in products:<br> yield {"name": product.css(...)}<br> | 在循环中逐个 yield 结果,避免内存占用过高,适合大量数据的情况。 |
结合请求和数据 | python<br>yield scrapy.Request(url1, callback=...)<br>yield {"data": ...}<br> | 同一个解析方法可以混合 yield 请求和数据,Scrapy 会分别处理。 |
委托生成器 | yield from self.parse_other(response) | (Python 3.3+)将生成操作委托给另一个生成器函数,通常用于模块化代码。 |
为什么不使用return
-
内存效率:yield逐个返回结果,避免一次性加载所有数据到内存
-
异步支持:Scrapy的异步架构依赖生成器实现高效调度
-
灵活性:可以在一个方法中yield多个不同类型的对象(请求或数据)
-
管道处理:yield的Item会自动进入Item Pipeline进行处理
注意事项
-
yield的对象必须是
Request
、Item
、dict
或None
之一 -
使用
yield from
可以委托给另一个生成器(在Python 3.3+) -
确保每个yield的对象都被正确处理,避免数据丢失
链接提取器
官网概念:链接提取器是从响应中提取链接的对象。
导入
from scrapy.linkextractors import LinkExtractor
使用
import scrapy
import os
from ..items import TestprojectItem
from scrapy.linkextractors import LinkExtractor
# 项目测试
class TestSpider(scrapy.Spider):
def __init__(self):
self.linkExtractor = LinkExtractor()
name = "test"
# 或者直接卸载头部的strt_url中 一样的 为什么知道这个方法 查看父类的spider 集成了 所以使用子类会自动覆盖父类相同方法
# 路劲注意 file:///是本地文件开头 如果是绝对路径自己直接写即可 如果是相对路径使用下面的即可
def start_requests(self):
# 获取当前目录的绝对路径
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, 'test.html')
# 替换反斜杠为正斜杠,并添加 file:/// 前缀
file_url = 'file:///' + file_path.replace('\\', '/')
yield scrapy.Request(url=file_url, callback=self.parse)
def parse(self, response):
# 链接提取器
for link in self.linkExtractor.extract_links(response):
print("testLink:",link)
print("testLink 获取属性:",link.__getattribute__("url"))
return item
Feed 导出
官网概念:在实现scraper时,最经常需要的功能之一是能够正确地存储被抓取的数据,这通常意味着用被抓取的数据(通常称为“导出提要”)生成一个“导出文件”,供其他系统使用。
支持多种导出格式:
-
JSON (
json
) -
JSON Lines (
jsonlines
) -
CSV (
csv
) -
XML (
xml
) -
Pickle (
pickle
) -
Marshal (
marshal
)
导入
settings中设置
# 每2条记录保存一个文件分批导出测试 FEED_EXPORT_BATCH_ITEM_COUNT = 2 # 全局导出的编码格式 FEED_EXPORT_ENCODING = 'utf-8' # 同时导出JSON和CSV FEEDS = { 'output/test_links_batch_%(batch_id)d.json': { 'format': 'json', 'encoding': 'utf8', 'indent': 4, 'fields': ['title', 'url'], # 指定导出的字段 'overwrite': True # 覆盖已存在的文件 }, 'output/test_links_batch_%(batch_id)d.csv': { 'format': 'csv', # 格式 'encoding': 'utf8', # 编码 'fields': ['title', 'url'], # 指定字段顺序 'overwrite': True # 覆盖已存在的文件 } }
使用
# feed 导出测试
for link in response.css('a'):
# yield 挨个处理任务
yield {
'url': link.attrib.get('href', '').strip(),
'title': link.css('::text').get('').strip()
}
常用方法
需要时查询即可,不用都练习、上面的能解决很多问题、分批次用的比较多吧。
基础配置参数
参数名 | 类型 | 默认值 | 描述 | 示例 |
---|---|---|---|---|
FEED_URI | 字符串 | None | 导出文件的URI路径 | 'file:///tmp/export.json' |
FEED_FORMAT | 字符串 | None | 导出格式(json, jsonlines, csv, xml等) | 'json' |
FEED_STORAGES | 字典 | 内置存储 | 自定义存储后端 | {'s3': 'myproject.storage.S3Storage'} |
FEED_STORAGE_PARAMS | 字典 | {} | 存储后端的参数 | {'access_key': 'xxx', 'secret_key': 'xxx'} |
FEED_EXPORTERS | 字典 | 内置导出器 | 自定义导出器 | {'myformat': 'myproject.exporters.MyExporter'} |
FEED_EXPORT_FIELDS | 列表 | None | 指定导出的字段及顺序 | ['title', 'price', 'url'] |
FEED_EXPORT_ENCODING | 字符串 | 'utf-8' | 导出文件的编码 | 'gbk' |
FEED_EXPORT_INDENT | 整数 | 0 | JSON导出的缩进(0表示紧凑格式) | 4 |
高级配置参数
参数名 | 类型 | 默认值 | 描述 | 示例 |
---|---|---|---|---|
FEED_STORE_EMPTY | 布尔 | False | 是否存储空结果 | True |
FEED_APPEND | 布尔 | False | 是否追加到现有文件 | True |
FEED_OVERWRITE | 布尔 | True | 是否覆盖现有文件 | False |
FEED_EXPORT_BATCH_ITEM_COUNT | 整数 | None | 分批导出时的每批数量 | 1000 |
FEED_EXPORTER_PARAMS | 字典 | {} | 导出器的额外参数 | {'ensure_ascii': False} |
存储后端特定参数
本地文件系统
参数名 | 描述 | 示例 |
---|---|---|
file:// 前缀 | 本地文件路径 | 'file:///path/to/export.json' |
FTP
参数名 | 描述 | 示例 |
---|---|---|
ftp:// 前缀 | FTP服务器路径 | 'ftp://user:pass@ftp.example.com/path/to/export.json' |
FEED_STORAGE_FTP_ACTIVE | 使用主动模式 | True |
S3
参数名 | 描述 | 示例 |
---|---|---|
s3:// 前缀 | S3路径 | 's3://bucket/path/to/export.json' |
AWS_ACCESS_KEY_ID | AWS访问密钥 | |
AWS_SECRET_ACCESS_KEY | AWS秘密密钥 | |
FEED_STORAGE_S3_ACL | 设置ACL权限 | 'private' |
命令行参数
参数 | 描述 | 示例 |
---|---|---|
-o FILE | 快捷导出文件 | -o items.json |
-O FILE | 覆盖导出文件 | -O items.json |
-t FORMAT | 指定导出格式 | -t csv |
请求与响应
官网概念:通常, Request 对象在spider中生成并在系统中传递,直到它们到达下载程序,下载程序执行请求并返回 Response 返回发出请求的spider的对象。在Scrapy中,scrapy.http.Request
和scrapy.Request
实际上是同一个类,但它们的导入方式不同。(功能完全相同且使用scrapy.request更常见,以下不用练习做个记录使用查询即可)
使用
from scrapy.http import Request
# 简单GET请求
request = Request(url='http://example.com')
# 带回调的请求
request = Request(
url='http://example.com/products',
callback=self.parse_products,
meta={'page': 1},
headers={'Referer': 'http://example.com'}
)
构造参数详解
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
url | str | 必填 | 请求的URL |
callback | callable | None | 响应处理函数 |
method | str | 'GET' | HTTP方法 |
headers | dict | None | 请求头 |
body | bytes/str | None | 请求体 |
cookies | dict/list | None | Cookies |
meta | dict | None | 请求元数据 |
encoding | str | 'utf-8' | 编码 |
priority | int | 0 | 优先级(0-1000) |
dont_filter | bool | False | 是否跳过去重 |
errback | callable | None | 错误处理函数 |
flags | list | None | 请求标志 |
cb_kwargs | dict | None | 回调函数的额外参数 |
常用方法和属性
核心属性
属性 | 类型 | 描述 | 示例 |
---|---|---|---|
url | str | 请求的URL | 'http://example.com' |
method | str | HTTP方法(GET/POST等) | 'GET' , 'POST' |
headers | dict | 请求头信息 | {'User-Agent': 'Mozilla'} |
body | bytes | 请求体内容 | b'name=value' |
meta | dict | 请求的元数据 | {'proxy': 'http://proxy:3128'} |
cookies | dict/list | 请求的Cookies | {'sessionid': '123abc'} |
encoding | str | 请求的编码 | 'utf-8' |
priority | int | 请求优先级(0-1000) | 500 |
dont_filter | bool | 是否不过滤重复请求 | True |
callback | callable | 响应回调函数 | self.parse_detail |
errback | callable | 错误回调函数 | self.error_handler |
cb_kwargs | dict | 回调函数的额外参数 | {'page': 2} |
常用方法
方法 | 描述 | 示例 |
---|---|---|
replace([url, method, headers, body, cookies, meta, encoding, callback, errback, cb_kwargs, dont_filter]) | 创建并返回新Request对象(替换指定属性) | new_request = request.replace(url=new_url) |
copy() | 创建Request的浅拷贝 | req_copy = request.copy() |
__str__() | 返回请求的字符串表示 | print(request) |
特殊属性/方法
属性/方法 | 描述 | 示例 |
---|---|---|
flags | 请求的标志列表 | request.flags.append('cached') |
fingerprint | 请求的唯一指纹(用于去重) | print(request.fingerprint) |
_set_url(url) | 设置URL(内部方法) | - |
_set_body(body) | 设置请求体(内部方法) | - |
元数据(meta)常用键
meta键 | 描述 | 示例 |
---|---|---|
dont_redirect | 禁止重定向 | meta={'dont_redirect': True} |
handle_httpstatus_list | 处理非常规状态码 | meta={'handle_httpstatus_list': [404, 500]} |
dont_retry | 禁止重试 | meta={'dont_retry': True} |
download_timeout | 下载超时(秒) | meta={'download_timeout': 60} |
proxy | 使用代理 | meta={'proxy': 'http://proxy:3128'} |
depth | 请求深度 | meta={'depth': 3} |
item | 传递Item对象 | meta={'item': item} |
代码路径:pythonPractice: python学习内容练习-代码