蜘蛛合约¶
测试蜘蛛可能会变得特别烦人,虽然没有什么能阻止你编写单元测试,但任务很快就会变得繁琐。Scrapy 提供了一种通过合同测试蜘蛛的集成方法。
这允许您通过硬编码一个示例URL来测试您的爬虫的每个回调,并检查回调处理响应的各种约束。每个合约都以@为前缀,并包含在文档字符串中。请参见以下示例:
def parse(self, response):
"""
This function parses a sample response. Some contracts are mingled
with this docstring.
@url http://www.example.com/s?field-keywords=selfish+gene
@returns items 1 16
@returns requests 0 0
@scrapes Title Author Year Price
"""
您可以使用以下合同:
- class scrapy.contracts.default.UrlContract[源代码]¶
此合同 (
@url) 设置了在检查此蜘蛛的其他合同条件时使用的示例URL。此合同是强制性的。在运行检查时,所有缺少此合同的回调都将被忽略:@url url
- class scrapy.contracts.default.CallbackKeywordArgumentsContract[source]¶
此合同 (
@cb_kwargs) 为示例请求设置了cb_kwargs属性。它必须是一个有效的 JSON 字典。@cb_kwargs {"arg1": "value1", "arg2": "value2", ...}
- class scrapy.contracts.default.MetadataContract[source]¶
此合同(
@meta)为示例请求设置了meta属性。它必须是一个有效的JSON字典。@meta {"arg1": "value1", "arg2": "value2", ...}
- class scrapy.contracts.default.ReturnsContract[source]¶
此合同 (
@returns) 为蜘蛛返回的项目和请求设置了上下限。上限是可选的:@returns item(s)|request(s) [min [max]]
- class scrapy.contracts.default.ScrapesContract[source]¶
此合同 (
@scrapes) 检查回调返回的所有项目是否具有指定的字段:@scrapes field_1 field_2 ...
使用check命令来运行合同检查。
自定义合同¶
如果你发现你需要比内置的Scrapy合约更多的功能,你可以通过使用SPIDER_CONTRACTS设置在项目中创建并加载你自己的合约:
SPIDER_CONTRACTS = {
"myproject.contracts.ResponseCheck": 10,
"myproject.contracts.ItemValidate": 10,
}
每个合同必须继承自 Contract 并且可以
重写三个方法:
- class scrapy.contracts.Contract(method, *args)[源代码]¶
- Parameters:
method (collections.abc.Callable) – 与合约关联的回调函数
args (list) – 传递给文档字符串的参数列表(以空格分隔)
- adjust_request_args(args)[source]¶
这接收一个
dict作为参数,包含请求对象的默认参数。默认情况下使用Request,但可以通过request_cls属性进行更改。如果链中的多个合约定义了此属性,则使用最后一个。必须返回相同或修改后的版本。
- pre_process(response)¶
这允许在将样本请求的响应传递给回调之前,对接收到的响应进行各种检查。
- post_process(output)¶
这允许处理回调的输出。在传递给此钩子之前,迭代器会被转换为列表。
如果期望未满足,从
ContractFail 或
pre_process 或
post_process 抛出异常:
这是一个演示合同,用于检查接收到的响应中是否存在自定义头:
from scrapy.contracts import Contract
from scrapy.exceptions import ContractFail
class HasHeaderContract(Contract):
"""
Demo contract which checks the presence of a custom header
@has_header X-CustomHeader
"""
name = "has_header"
def pre_process(self, response):
for header in self.args:
if header not in response.headers:
raise ContractFail("X-CustomHeader not present")
检测检查运行¶
当 scrapy check 运行时,SCRAPY_CHECK 环境变量被设置为 true 字符串。你可以使用 os.environ 在 scrapy check 被使用时对你的爬虫或设置进行任何更改:
import os
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example"
def __init__(self):
if os.environ.get("SCRAPY_CHECK"):
pass # Do some scraper adjustments when a check is running