请求和响应

Scrapy 使用 RequestResponse 对象来抓取网站。

通常,Request 对象在 spider 中生成,并在系统中传递,直到到达 Downloader(下载器)。Downloader 执行请求并返回一个 Response 对象,该对象再返回给发出请求的 spider。

RequestResponse 类都有子类,这些子类添加了基类不需要的功能。这些内容将在下面的 Request 子类Response 子类 中描述。

Request 对象

class scrapy.Request(*args: Any, **kwargs: Any)[source]

表示一个 HTTP 请求,通常在 Spider 中生成并由 Downloader 执行,从而生成一个 Response

参数:
  • url (str) –

    此请求的 URL

    如果 URL 无效,则会引发 ValueError 异常。

  • callback (Callable[Concatenate[Response, ...], Any] | None) –

    设置 callback,默认为 None

    版本 2.0 中有改动: 指定 errback 参数时,不再需要 callback 参数。

  • method (str) – 此请求的 HTTP 方法。默认为 'GET'

  • meta (dict) – Request.meta 属性的初始值。如果提供,此参数中传递的字典将被浅拷贝。

  • body (bytesstr) – 请求体。如果传入字符串,则会使用传入的 encoding(默认为 utf-8)将其编码为字节。如果未提供 body,则存储一个空的字节对象。无论此参数的类型如何,最终存储的值都将是一个字节对象(绝不是字符串或 None)。

  • headers (dict) –

    此请求的请求头。字典值可以是字符串(用于单值请求头)或列表(用于多值请求头)。如果传递 None 作为值,则完全不会发送该 HTTP 请求头。

    注意

    通过 Cookie 请求头设置的 Cookie 不会被 CookiesMiddleware 考虑。如果需要为请求设置 Cookie,请使用 cookies 参数。这是一个目前已知并在处理中的限制。

  • cookies (dictlist) –

    请求的 Cookie。可以通过两种形式发送。

    1. 使用字典

    request_with_cookies = Request(
        url="http://www.example.com",
        cookies={"currency": "USD", "country": "UY"},
    )
    
    1. 使用字典列表

    request_with_cookies = Request(
        url="https://www.example.com",
        cookies=[
            {
                "name": "currency",
                "value": "USD",
                "domain": "example.com",
                "path": "/currency",
                "secure": True,
            },
        ],
    )
    

    后一种形式允许自定义 Cookie 的 domainpath 属性。这仅在 Cookie 保存用于后续请求时有用。

    当某个网站返回 Cookie(在响应中)时,这些 Cookie 将存储在该域的 Cookie 中,并在未来的请求中再次发送。这是任何常规 Web 浏览器的典型行为。

    请注意,在 request.meta 中将 dont_merge_cookies 键设置为 True 会导致自定义 Cookie 被忽略。

    更多信息请参阅 CookiesMiddleware

    注意

    通过 Cookie 请求头设置的 Cookie 不会被 CookiesMiddleware 考虑。如果需要为请求设置 Cookie,请使用 scrapy.Request.cookies 参数。这是一个目前已知并在处理中的限制。

    在版本 2.6.0 中新增: 类型为 bool, floatint 的 Cookie 值会被转换为 str

  • encoding (str) – 此请求的编码(默认为 'utf-8')。此编码将用于对 URL 进行百分比编码,并将请求体转换为字节(如果作为字符串提供)。

  • priority (int) – 设置 priority,默认为 0

  • dont_filter (bool) – 设置 dont_filter,默认为 False

  • errback (Callable[[Failure], Any] | None) –

    设置 errback,默认为 None

    版本 2.0 中有改动: 指定 errback 参数时,不再需要 callback 参数。

  • flags (list) – 发送给请求的标志,可用于日志记录或类似目的。

  • cb_kwargs (dict) – 一个包含任意数据的字典,这些数据将作为关键字参数传递给 Request 的回调函数。

url

一个包含此请求 URL 的字符串。请记住,此属性包含已转义的 URL,因此它可能与 __init__() 方法中传递的 URL 不同。

此属性是只读的。要更改 Request 的 URL,请使用 replace()

method

表示请求中 HTTP 方法的字符串。保证为大写。示例:"GET", "POST", "PUT"

headers

一个类似字典的 (scrapy.http.headers.Headers) 对象,包含请求头。

body

作为字节的请求体。

此属性是只读的。要更改 Request 的请求体,请使用 replace()

callback: CallbackT | None

用于解析此请求收到后的 ResponseCallable 对象。

可调用对象必须将响应作为其第一个参数,并支持通过 cb_kwargs 设置的任何额外关键字参数。

除了任意可调用对象外,还支持以下值

如果在请求或响应处理期间发生未处理的异常,例如由 spider 中间件下载器中间件 或下载处理程序 (DOWNLOAD_HANDLERS) 引发,则会改为调用 errback

提示

HttpErrorMiddleware 默认会针对非 2xx 响应引发异常,并将其发送到 errback

errback: Callable[[Failure], Any] | None

用于处理请求或响应处理期间引发的异常的 Callable 对象。

可调用对象必须将 Failure 作为其第一个参数。

priority: int

默认值: 0

调度器 可能用于请求优先级排序的值。

内置调度器会优先处理优先级值更高的请求。

允许使用负值。

cb_kwargs

一个包含此请求的任意元数据的字典。其内容将作为关键字参数传递给 Request 的回调函数。对于新的 Request,它为空,这意味着默认情况下回调函数只接收一个 Response 对象作为参数。

当使用 copy()replace() 方法克隆请求时,此字典会进行 浅拷贝,并且在 spider 中,也可以通过 response.cb_kwargs 属性访问它。

如果处理请求失败,可以在请求的 errback 中通过 failure.request.cb_kwargs 访问此字典。更多信息请参阅 在 errback 函数中访问额外数据

meta = {}

一个包含请求的任意元数据的字典。

您可以根据需要扩展请求元数据。

请求元数据也可以通过响应的 meta 属性访问。

要在不同的 spider 回调函数之间传递数据,请考虑使用 cb_kwargs。然而,在某些情况下,请求元数据可能是正确的选择,例如在所有后续请求中维护一些调试数据(例如源 URL)。

请求元数据的一个常见用途是为 Scrapy 组件(扩展、中间件等)定义请求特定的参数。例如,如果您将 dont_retry 设置为 True,即使请求失败,RetryMiddleware 也不会重试该请求。请参阅 Request.meta 特殊键

您也可以在自定义的 Scrapy 组件中使用请求元数据,例如,保存与您的组件相关的请求状态信息。例如,RetryMiddleware 使用 retry_times 元数据键来跟踪请求目前已重试的次数。

在 spider 回调函数中,将前一个请求的所有元数据复制到新的、后续请求中是一种不良实践,因为请求元数据可能包含由 Scrapy 组件设置的元数据,这些元数据不应该被复制到其他请求中。例如,将 retry_times 元数据键复制到后续请求中,可能会降低这些后续请求允许的重试次数。

只有当新请求旨在替换旧请求时,才应该将一个请求的所有元数据复制到另一个请求中,这通常发生在从 下载器中间件 方法返回请求时。

另请注意,copy()replace() 请求方法会 浅拷贝 请求元数据。

dont_filter: bool

此请求是否可以被支持过滤请求的 组件 过滤掉(False,默认),还是这些组件不应该过滤掉此请求(True)。

此属性通常设置为 True,以防止重复请求被过滤掉。

通过 start_urls 定义 spider 的起始 URL 时,此属性默认启用。请参阅 start()

attributes: tuple[str, ...] = ('url', 'callback', 'method', 'headers', 'body', 'cookies', 'meta', 'encoding', 'priority', 'dont_filter', 'errback', 'flags', 'cb_kwargs')

一个由 str 对象组成的元组,包含类中所有公共属性的名称,这些属性也是 __init__() 方法的关键字参数。

目前被 Request.replace(), Request.to_dict()request_from_dict() 使用。

copy()[source]

返回一个新的 Request,它是此 Request 的副本。另请参阅:向回调函数传递额外数据

replace([url, method, headers, body, cookies, meta, flags, encoding, priority, dont_filter, callback, errback, cb_kwargs])[source]

返回一个 Request 对象,其成员与原对象相同,但通过关键字参数指定新值的成员除外。cb_kwargsmeta 属性默认进行浅拷贝(除非作为参数提供了新值)。另请参阅 向回调函数传递额外数据

classmethod from_curl(curl_command: str, ignore_unknown_options: bool = True, **kwargs: Any) Self[source]

从包含 cURL 命令的字符串创建 Request 对象。它填充 HTTP 方法、URL、请求头、Cookie 和请求体。它接受与 Request 类相同的参数,并优先使用这些参数值,覆盖 cURL 命令中包含的相同参数值。

默认情况下,不识别的选项会被忽略。要在发现未知选项时引发错误,请在调用此方法时传递 ignore_unknown_options=False

注意

使用来自 Request 子类(如 JsonRequestXmlRpcRequest)的 from_curl(),以及启用 下载器中间件spider 中间件(例如 DefaultHeadersMiddleware, UserAgentMiddlewareHttpCompressionMiddleware),可能会修改 Request 对象。

要将 cURL 命令转换为 Scrapy 请求,您可以使用 curl2scrapy

to_dict(*, spider: Spider | None = None) dict[str, Any][source]

返回一个包含 Request 数据的字典。

使用 request_from_dict() 将其转换回一个 Request 对象。

如果给定了爬虫,该方法将尝试找出用作回调 (callback) 和错误回调 (errback) 的爬虫方法的名称,并将它们包含在输出字典中;如果找不到,则会引发异常。

向回调函数传递额外数据

请求的回调是一个函数,当该请求的响应被下载后将被调用。回调函数将以下载的 Response 对象作为第一个参数被调用。

示例

def parse_page1(self, response):
    return scrapy.Request(
        "http://www.example.com/some_page.html", callback=self.parse_page2
    )


def parse_page2(self, response):
    # this would log http://www.example.com/some_page.html
    self.logger.info("Visited %s", response.url)

在某些情况下,您可能希望向这些回调函数传递参数,以便稍后在第二个回调中接收这些参数。以下示例展示了如何通过使用 Request.cb_kwargs 属性来实现这一点。

def parse(self, response):
    request = scrapy.Request(
        "http://www.example.com/index.html",
        callback=self.parse_page2,
        cb_kwargs=dict(main_url=response.url),
    )
    request.cb_kwargs["foo"] = "bar"  # add more arguments for the callback
    yield request


def parse_page2(self, response, main_url, foo):
    yield dict(
        main_url=main_url,
        other_url=response.url,
        foo=foo,
    )

注意

Request.cb_kwargs 在版本 1.7 中引入。在此之前,建议使用 Request.meta 来在回调之间传递信息。在 1.7 之后,Request.cb_kwargs 成为处理用户信息的首选方式,而 Request.meta 则保留用于与中间件 (middlewares) 和扩展 (extensions) 等组件通信。

使用错误回调 (errbacks) 捕获请求处理中的异常

请求的错误回调是一个函数,当在处理请求时发生异常时将被调用。

它接收一个 Failure 对象作为第一个参数,可用于跟踪连接建立超时、DNS 错误等。

这里有一个示例爬虫,用于记录所有错误并在需要时捕获一些特定错误。

import scrapy

from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutError


class ErrbackSpider(scrapy.Spider):
    name = "errback_example"
    start_urls = [
        "http://www.httpbin.org/",  # HTTP 200 expected
        "http://www.httpbin.org/status/404",  # Not found error
        "http://www.httpbin.org/status/500",  # server issue
        "http://www.httpbin.org:12345/",  # non-responding host, timeout expected
        "https://example.invalid/",  # DNS error expected
    ]

    async def start(self):
        for u in self.start_urls:
            yield scrapy.Request(
                u,
                callback=self.parse_httpbin,
                errback=self.errback_httpbin,
                dont_filter=True,
            )

    def parse_httpbin(self, response):
        self.logger.info("Got successful response from {}".format(response.url))
        # do something useful here...

    def errback_httpbin(self, failure):
        # log all failures
        self.logger.error(repr(failure))

        # in case you want to do something special for some errors,
        # you may need the failure's type:

        if failure.check(HttpError):
            # these exceptions come from HttpError spider middleware
            # you can get the non-200 response
            response = failure.value.response
            self.logger.error("HttpError on %s", response.url)

        elif failure.check(DNSLookupError):
            # this is the original request
            request = failure.request
            self.logger.error("DNSLookupError on %s", request.url)

        elif failure.check(TimeoutError, TCPTimedOutError):
            request = failure.request
            self.logger.error("TimeoutError on %s", request.url)

在错误回调函数中访问额外数据

如果请求处理失败,您可能需要访问回调函数的参数,以便在错误回调中根据这些参数进行进一步处理。以下示例展示了如何通过使用 Failure.request.cb_kwargs 来实现这一点。

def parse(self, response):
    request = scrapy.Request(
        "http://www.example.com/index.html",
        callback=self.parse_page2,
        errback=self.errback_page2,
        cb_kwargs=dict(main_url=response.url),
    )
    yield request


def parse_page2(self, response, main_url):
    pass


def errback_page2(self, failure):
    yield dict(
        main_url=failure.request.cb_kwargs["main_url"],
    )

请求指纹

在爬取的一些方面,例如过滤重复请求(参见 DUPEFILTER_CLASS)或缓存响应(参见 HTTPCACHE_POLICY),您需要能够从 Request 对象生成一个简短、唯一的标识符:一个请求指纹。

通常您无需担心请求指纹,默认的请求指纹生成器适用于大多数项目。

然而,没有一种通用的方法可以从请求生成唯一的标识符,因为不同的情况需要以不同的方式比较请求。例如,有时您可能需要不区分大小写地比较 URL,包含 URL 片段,排除某些 URL 查询参数,包含部分或全部请求头等。

要更改请求指纹的构建方式,请使用 REQUEST_FINGERPRINTER_CLASS 设置。

REQUEST_FINGERPRINTER_CLASS

在版本 2.7 中新增。

默认值:scrapy.utils.request.RequestFingerprinter

一个 请求指纹生成器类 或其导入路径。

class scrapy.utils.request.RequestFingerprinter(crawler: Crawler | None = None)[source]

默认的指纹生成器。

它考虑了 request.url 的规范化版本(w3lib.url.canonicalize_url())以及 request.methodrequest.body 的值。然后生成一个 SHA1 哈希。

编写自己的请求指纹生成器

请求指纹生成器是一个 组件,必须实现以下方法。

fingerprint(self, request: scrapy.Request)

返回一个唯一标识 *request* 的 bytes 对象。

另请参见 请求指纹限制

默认请求指纹生成器 scrapy.utils.request.RequestFingerprinterfingerprint() 方法使用了 scrapy.utils.request.fingerprint() 的默认参数。对于一些常见的使用场景,您也可以在自己的 fingerprint() 方法实现中使用 scrapy.utils.request.fingerprint()

scrapy.utils.request.fingerprint(request: Request, *, include_headers: Iterable[bytes | str] | None = None, keep_fragments: bool = False) bytes[source]

返回请求指纹。

请求指纹是一个哈希值,用于唯一标识请求指向的资源。例如,考虑以下两个 URL:http://www.example.com/query?id=111&cat=222http://www.example.com/query?cat=222&id=111

尽管这是两个不同的 URL,但它们都指向同一资源并且是等效的(即它们应该返回相同的响应)。

另一个例子是用于存储会话 ID 的 cookie。假设以下页面仅供认证用户访问:http://www.example.com/members/offers.html

许多网站使用 cookie 来存储会话 ID,这会给 HTTP 请求添加一个随机成分,因此在计算指纹时应该忽略它。

因此,在计算指纹时默认忽略请求头。如果要包含特定的请求头,请使用 include_headers 参数,它是一个要包含的 Request 请求头列表。

此外,服务器在处理请求时通常会忽略 URL 中的片段,因此在计算指纹时默认也会忽略它们。如果您想包含它们,请将 keep_fragments 参数设置为 True(例如在使用无头浏览器处理请求时)。

例如,要将名为 X-ID 的请求头的值考虑在内。

# my_project/settings.py
REQUEST_FINGERPRINTER_CLASS = "my_project.utils.RequestFingerprinter"

# my_project/utils.py
from scrapy.utils.request import fingerprint


class RequestFingerprinter:
    def fingerprint(self, request):
        return fingerprint(request, include_headers=["X-ID"])

您也可以从头开始编写自己的指纹生成逻辑。

然而,如果您不使用 scrapy.utils.request.fingerprint(),请确保使用 WeakKeyDictionary 来缓存请求指纹。

  • 缓存通过确保每个请求的指纹只计算一次,而不是每个需要请求指纹的 Scrapy 组件都计算一次,从而节省 CPU。

  • 使用 WeakKeyDictionary 通过确保请求对象不会仅仅因为您的缓存字典中引用了它们而永远保留在内存中,从而节省内存。

例如,仅考虑请求的 URL,而无需进行任何 URL 规范化或考虑请求方法或请求体。

from hashlib import sha1
from weakref import WeakKeyDictionary

from scrapy.utils.python import to_bytes


class RequestFingerprinter:
    cache = WeakKeyDictionary()

    def fingerprint(self, request):
        if request not in self.cache:
            fp = sha1()
            fp.update(to_bytes(request.url))
            self.cache[request] = fp.digest()
        return self.cache[request]

如果您需要能够从爬虫回调中覆盖任意请求的指纹生成,您可以实现一个请求指纹生成器,在可用时从 request.meta 中读取指纹,然后回退到 scrapy.utils.request.fingerprint()。例如

from scrapy.utils.request import fingerprint


class RequestFingerprinter:
    def fingerprint(self, request):
        if "fingerprint" in request.meta:
            return request.meta["fingerprint"]
        return fingerprint(request)

如果您需要重现与 Scrapy 2.6 相同的指纹算法,请使用以下请求指纹生成器。

from hashlib import sha1
from weakref import WeakKeyDictionary

from scrapy.utils.python import to_bytes
from w3lib.url import canonicalize_url


class RequestFingerprinter:
    cache = WeakKeyDictionary()

    def fingerprint(self, request):
        if request not in self.cache:
            fp = sha1()
            fp.update(to_bytes(request.method))
            fp.update(to_bytes(canonicalize_url(request.url)))
            fp.update(request.body or b"")
            self.cache[request] = fp.digest()
        return self.cache[request]

请求指纹限制

使用请求指纹的 Scrapy 组件可能会对您的 请求指纹生成器 生成的指纹格式施加额外的限制。

以下内置的 Scrapy 组件具有此类限制。

  • scrapy.extensions.httpcache.FilesystemCacheStorage (HTTPCACHE_STORAGE 的默认值)

    请求指纹必须至少为 1 字节长。

    HTTPCACHE_DIR 文件系统的路径和文件名长度限制也适用。在 HTTPCACHE_DIR 内部,会创建以下目录结构:

    • 爬虫名

      • 请求指纹的第一个字节(十六进制表示)

        • 指纹(十六进制表示)

          • 文件名(最长 16 个字符)

    例如,如果一个请求指纹由 20 字节组成(默认),HTTPCACHE_DIR'/home/user/project/.scrapy/httpcache',并且您的爬虫名称是 'my_spider',则您的文件系统必须支持类似以下的文件路径:

    /home/user/project/.scrapy/httpcache/my_spider/01/0123456789abcdef0123456789abcdef01234567/response_headers
    
  • scrapy.extensions.httpcache.DbmCacheStorage

    底层的 DBM 实现必须支持长度为请求指纹字节数的两倍加 5 的键。例如,如果一个请求指纹由 20 字节组成(默认),则必须支持长度为 45 个字符的键。

Request.meta 特殊键

通过 Request.meta 属性可以包含任意数据,但有一些由 Scrapy 及其内置扩展识别的特殊键。

这些键包括:

bindaddress

用于执行请求的出站 IP 地址。

download_timeout

下载器在超时前等待的时间(秒)。另请参见:DOWNLOAD_TIMEOUT

download_latency

从请求开始(即 HTTP 消息通过网络发送)到获取响应所花费的时间。这个 meta 键只在响应下载完成后可用。虽然大多数其他 meta 键用于控制 Scrapy 的行为,但这个键应被视为只读。

download_fail_on_dataloss

是否在响应损坏时失败。参见:DOWNLOAD_FAIL_ON_DATALOSS

max_retry_times

这个 meta 键用于设置每个请求的重试次数。初始化时,max_retry_times meta 键的优先级高于 RETRY_TIMES 设置。

停止下载响应

bytes_receivedheaders_received 信号的处理程序中引发 StopDownload 异常将停止给定响应的下载。参见以下示例:

import scrapy


class StopSpider(scrapy.Spider):
    name = "stop"
    start_urls = ["https://docs.scrapy.net.cn/en/latest/"]

    @classmethod
    def from_crawler(cls, crawler):
        spider = super().from_crawler(crawler)
        crawler.signals.connect(
            spider.on_bytes_received, signal=scrapy.signals.bytes_received
        )
        return spider

    def parse(self, response):
        # 'last_chars' show that the full response was not downloaded
        yield {"len": len(response.text), "last_chars": response.text[-40:]}

    def on_bytes_received(self, data, request, spider):
        raise scrapy.exceptions.StopDownload(fail=False)

这会产生以下输出:

2020-05-19 17:26:12 [scrapy.core.engine] INFO: Spider opened
2020-05-19 17:26:12 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-05-19 17:26:13 [scrapy.core.downloader.handlers.http11] DEBUG: Download stopped for <GET https://docs.scrapy.org/en/latest/> from signal handler StopSpider.on_bytes_received
2020-05-19 17:26:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://docs.scrapy.org/en/latest/> (referer: None) ['download_stopped']
2020-05-19 17:26:13 [scrapy.core.scraper] DEBUG: Scraped from <200 https://docs.scrapy.org/en/latest/>
{'len': 279, 'last_chars': 'dth, initial-scale=1.0">\n  \n  <title>Scr'}
2020-05-19 17:26:13 [scrapy.core.engine] INFO: Closing spider (finished)

默认情况下,结果响应由其相应的错误回调处理。要像本例一样调用其回调而不是错误回调,请将 fail=False 传递给 StopDownload 异常。

Request 子类

以下是内置的 Request 子类列表。您也可以继承它来实现您自己的自定义功能。

FormRequest 对象

FormRequest 类扩展了基本的 Request 类,提供了处理 HTML 表单的功能。它使用 lxml.html forms 根据 Response 对象中的表单数据预填充表单字段。

class scrapy.FormRequest(url[, formdata, ...])

FormRequest 类为 __init__() 方法添加了一个新的关键字参数。其余参数与 Request 类相同,在此不再赘述。

参数:

formdata (dict or collections.abc.Iterable) – 是一个字典(或 (键, 值) 元组的可迭代对象),包含 HTML 表单数据,这些数据将被进行 URL 编码并赋值给请求的 body。

FormRequest 对象除了支持标准的 Request 方法外,还支持以下类方法:

classmethod from_response(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])

返回一个新的 FormRequest 对象,其表单字段值预填充了给定响应中包含的 HTML <form> 元素中的值。有关示例,请参阅 使用 FormRequest.from_response() 模拟用户登录

默认情况下,策略是自动模拟点击任何看起来可点击的表单控件,例如 <input type="submit">。尽管这非常方便,并且通常是期望的行为,但有时它可能会导致难以调试的问题。例如,在使用通过 javascript 填充和/或提交的表单时,默认的 from_response() 行为可能不是最合适的。要禁用此行为,可以将 dont_click 参数设置为 True。另外,如果您想更改被点击的控件(而不是禁用它),您也可以使用 clickdata 参数。

注意

由于 lxml 中的一个错误,在选项值中包含前导或尾随空白的 select 元素上使用此方法将不起作用,该错误应在 lxml 3.8 及更高版本中修复。

参数:
  • response (Response 对象) – 包含将用于预填充表单字段的 HTML 表单的响应

  • formname (str) – 如果给定,将使用 name 属性设置为此值的表单。

  • formid (str) – 如果给定,将使用 id 属性设置为此值的表单。

  • formxpath (str) – 如果给定,将使用第一个匹配 xpath 的表单。

  • formcss (str) – 如果给定,将使用第一个匹配 css 选择器的表单。

  • formnumber (int) – 当响应包含多个表单时要使用的表单编号。第一个(也是默认值)是 0

  • formdata (dict) – 要在表单数据中覆盖的字段。如果一个字段已存在于响应的 <form> 元素中,则其值将被此参数中传递的值覆盖。如果此参数中传递的值是 None,则该字段将不会包含在请求中,即使它存在于响应的 <form> 元素中。

  • clickdata (dict) – 用于查找被点击控件的属性。如果未给定,则将模拟点击第一个可点击元素来提交表单数据。除了 html 属性外,还可以通过相对于表单内其他可提交输入的从零开始的索引(通过 nr 属性)来识别控件。

  • dont_click (bool) – 如果为 True,将不点击任何元素直接提交表单数据。

此类方法的其他参数直接传递给 FormRequest__init__() 方法。

请求使用示例

使用 FormRequest 通过 HTTP POST 发送数据

如果您想在爬虫中模拟 HTML 表单 POST 并发送一些键值字段,您可以像这样从爬虫中返回一个 FormRequest 对象

return [
    FormRequest(
        url="http://www.example.com/post/action",
        formdata={"name": "John Doe", "age": "27"},
        callback=self.after_post,
    )
]

使用 FormRequest.from_response() 模拟用户登录

网站通常会通过 <input type="hidden"> 元素提供预填充的表单字段,例如会话相关数据或身份验证令牌(用于登录页面)。在抓取时,您会希望这些字段被自动预填充,并且只覆盖其中几个,例如用户名和密码。您可以使用 FormRequest.from_response() 方法来完成此工作。以下是使用此方法的一个爬虫示例

import scrapy


def authentication_failed(response):
    # TODO: Check the contents of the response and return True if it failed
    # or False if it succeeded.
    pass


class LoginSpider(scrapy.Spider):
    name = "example.com"
    start_urls = ["http://www.example.com/users/login.php"]

    def parse(self, response):
        return scrapy.FormRequest.from_response(
            response,
            formdata={"username": "john", "password": "secret"},
            callback=self.after_login,
        )

    def after_login(self, response):
        if authentication_failed(response):
            self.logger.error("Login failed")
            return

        # continue scraping with authenticated session...

JsonRequest

JsonRequest 类扩展了基本的 Request 类,增加了处理 JSON 请求的功能。

class scrapy.http.JsonRequest(url[, ... data, dumps_kwargs])[source]

JsonRequest 类在 __init__() 方法中增加了两个新的关键字参数。其余参数与 Request 类相同,在此不再赘述。

使用 JsonRequest 将把 Content-Type 请求头设置为 application/json,将 Accept 请求头设置为 application/json, text/javascript, */*; q=0.01

参数:
  • data (object) – 任何需要进行 JSON 编码并分配给 body 的可 JSON 序列化对象。如果提供了 body 参数,则此参数将被忽略。如果未提供 body 参数但提供了 data 参数,则 method 将自动设置为 'POST'

  • dumps_kwargs (dict) – 将传递给底层 json.dumps() 方法的参数,该方法用于将数据序列化为 JSON 格式。

attributes: tuple[str, ...] = ('url', 'callback', 'method', 'headers', 'body', 'cookies', 'meta', 'encoding', 'priority', 'dont_filter', 'errback', 'flags', 'cb_kwargs', 'dumps_kwargs')

一个由 str 对象组成的元组,包含类中所有公共属性的名称,这些属性也是 __init__() 方法的关键字参数。

目前被 Request.replace(), Request.to_dict()request_from_dict() 使用。

JsonRequest 使用示例

发送带有 JSON 有效载荷的 JSON POST 请求

data = {
    "name1": "value1",
    "name2": "value2",
}
yield JsonRequest(url="http://www.example.com/post/action", data=data)

Response 对象

class scrapy.http.Response(*args: Any, **kwargs: Any)[source]

表示 HTTP 响应的对象,通常由下载器(Downloader)下载并提供给爬虫(Spiders)进行处理。

参数:
  • url (str) – 此响应的 URL

  • status (int) – 响应的 HTTP 状态。默认为 200

  • headers (dict) – 此响应的头部信息。字典值可以是字符串(对于单值头部)或列表(对于多值头部)。

  • body (bytes) – 响应正文。要以字符串形式访问解码后的文本,请使用具有编码感知能力的 Response 子类(例如 TextResponse)中的 response.text

  • flags (list) – 一个列表,包含 Response.flags 属性的初始值。如果给定,该列表将被浅复制。

  • request (scrapy.Request) – Response.request 属性的初始值。这表示生成此响应的 Request

  • certificate (twisted.internet.ssl.Certificate) – 表示服务器 SSL 证书的对象。

  • ip_address (ipaddress.IPv4Addressipaddress.IPv6Address) – 响应来自的服务器的 IP 地址。

  • protocol (str) – 用于下载响应的协议。例如:“HTTP/1.0”、“HTTP/1.1”、“h2”

2.0.0 版新增: certificate 参数。

2.1.0 版新增: ip_address 参数。

2.5.0 版新增: protocol 参数。

url

包含响应 URL 的字符串。

此属性是只读的。要更改 Response 的 URL,请使用 replace()

status

表示响应 HTTP 状态的整数。示例:200404

headers

一个类似字典(scrapy.http.headers.Headers)的对象,包含响应头部信息。可以使用 get() 访问值以返回具有指定名称的第一个头部值,或使用 getlist() 返回具有指定名称的所有头部值。例如,此调用将返回头部中的所有 cookie

response.headers.getlist('Set-Cookie')
body

响应正文(以 bytes 为单位)。

如果您想要字符串形式的正文,请使用 TextResponse.text(仅在 TextResponse 及其子类中可用)。

此属性是只读的。要更改 Response 的正文,请使用 replace()

request

生成此响应的 Request 对象。此属性在 Scrapy 引擎中分配,在响应和请求通过所有 Downloader Middlewares 后。特别地,这意味着

  • HTTP 重定向将从重定向之前的请求创建一个新请求。它拥有与原始请求大部分相同的元数据和属性,并被分配给重定向后的响应,而不是原始请求的传播。

  • Response.request.url 并不总是等于 Response.url

  • 此属性仅在爬虫代码和 Spider Middlewares 中可用,但在 Downloader Middlewares(尽管您可以通过其他方式在那里获得 Request)和 response_downloaded 信号的处理程序中不可用。

meta

Response.request 对象的 meta 属性的快捷方式(即 self.request.meta)。

Response.request 属性不同,Response.meta 属性会沿着重定向和重试传播,因此您将获得从爬虫发送的原始 Request.meta

另请参阅

Request.meta 属性

cb_kwargs

2.0 版新增。

Response.request 对象的 cb_kwargs 属性的快捷方式(即 self.request.cb_kwargs)。

Response.request 属性不同,Response.cb_kwargs 属性会沿着重定向和重试传播,因此您将获得从爬虫发送的原始 Request.cb_kwargs

另请参阅

Request.cb_kwargs 属性

flags

包含此响应标志的列表。标志是用于标记 Response 的标签。例如:'cached''redirected’ 等。它们显示在 Response 的字符串表示中(__str__() 方法),引擎使用它进行日志记录。

certificate

2.0.0 版新增。

一个 twisted.internet.ssl.Certificate 对象,表示服务器的 SSL 证书。

仅针对 https 响应填充,否则为 None

ip_address

2.1.0 版新增。

响应来自的服务器的 IP 地址。

当前此属性仅由 HTTP 1.1 下载处理程序填充,即对于 http(s) 响应。对于其他处理程序,ip_address 始终为 None

protocol

2.5.0 版新增。

用于下载响应的协议。例如:“HTTP/1.0”、“HTTP/1.1”

当前此属性仅由 HTTP 下载处理程序填充,即对于 http(s) 响应。对于其他处理程序,protocol 始终为 None

attributes: tuple[str, ...] = ('url', 'status', 'headers', 'body', 'flags', 'request', 'certificate', 'ip_address', 'protocol')

一个由 str 对象组成的元组,包含类中所有公共属性的名称,这些属性也是 __init__() 方法的关键字参数。

当前由 Response.replace() 使用。

copy()[source]

返回此 Response 的一个新副本。

replace([url, status, headers, body, request, flags, cls])[source]

返回一个 Response 对象,其成员与原对象相同,但通过指定的关键字参数赋予新值的成员除外。Response.meta 属性默认被复制。

urljoin(url)[source]

通过将 Response 的 url 与可能的相对 url 组合来构造一个绝对 url。

这是对 urljoin() 的包装,它仅仅是执行此调用的一个别名

urllib.parse.urljoin(response.url, url)
follow(url: str | Link, callback: CallbackT | None = None, method: str = 'GET', headers: Mapping[AnyStr, Any] | Iterable[tuple[AnyStr, Any]] | None = None, body: bytes | str | None = None, cookies: CookiesT | None = None, meta: dict[str, Any] | None = None, encoding: str | None = 'utf-8', priority: int = 0, dont_filter: bool = False, errback: Callable[[Failure], Any] | None = None, cb_kwargs: dict[str, Any] | None = None, flags: list[str] | None = None) Request[source]

返回一个 Request 实例,用于跟踪一个链接 url。它接受与 Request.__init__() 方法相同的参数,但 url 可以是相对 URL 或 Link 对象,而不仅仅是绝对 URL。

TextResponse 提供了 follow() 方法,除了支持绝对/相对 URL 和 Link 对象外,还支持选择器。

2.0 版本加入: 参数 flags

follow_all(urls: Iterable[str | Link], callback: CallbackT | None = None, method: str = 'GET', headers: Mapping[AnyStr, Any] | Iterable[tuple[AnyStr, Any]] | None = None, body: bytes | str | None = None, cookies: CookiesT | None = None, meta: dict[str, Any] | None = None, encoding: str | None = 'utf-8', priority: int = 0, dont_filter: bool = False, errback: Callable[[Failure], Any] | None = None, cb_kwargs: dict[str, Any] | None = None, flags: list[str] | None = None) Iterable[Request][source]

2.0 版新增。

返回一个 Request 实例的可迭代对象,用于跟踪 urls 中的所有链接。它接受与 Request.__init__() 方法相同的参数,但 urls 的元素可以是相对 URL 或 Link 对象,而不仅仅是绝对 URL。

TextResponse 提供了 follow_all() 方法,除了支持绝对/相对 URL 和 Link 对象外,还支持选择器。

Response 子类

以下是可用的内置 Response 子类列表。您也可以子类化 Response 类来实现您自己的功能。

TextResponse 对象

class scrapy.http.TextResponse(url[, encoding[, ...]])[source]

TextResponse 对象在基础 Response 类(该类仅用于二进制数据,如图像、声音或任何媒体文件)的基础上增加了编码能力。

TextResponse 对象除了基础 Response 对象外,还支持一个新的 __init__() 方法参数。其余功能与 Response 类相同,此处不再赘述。

参数:

encoding (str) – 一个字符串,包含用于此响应的编码。如果您使用字符串作为正文创建一个 TextResponse 对象,它将被转换为使用此编码编码的字节。如果 encodingNone(默认),编码将改为在响应头和正文中查找。

TextResponse 对象除了标准 Response 对象外,还支持以下属性:

text

响应体,作为字符串。

response.body.decode(response.encoding) 相同,但结果会在首次调用后缓存,因此您可以多次访问 response.text 而没有额外开销。

注意

str(response.body) 不是将响应体转换为字符串的正确方法

>>> str(b"body")
"b'body'"
encoding

一个字符串,包含此响应的编码。编码通过尝试以下机制按顺序解析:

  1. __init__() 方法的 encoding 参数中传递的编码

  2. 在 Content-Type HTTP 头中声明的编码。如果此编码无效(即未知),则忽略并尝试下一个解析机制。

  3. 在响应体中声明的编码。TextResponse 类对此不提供任何特殊功能。但是,HtmlResponseXmlResponse 类提供了。

  4. 通过查看响应体推断出的编码。这是更脆弱的方法,但也是最后尝试的方法。

selector

一个以响应为目标的 Selector 实例。选择器在首次访问时延迟实例化。

attributes: tuple[str, ...] = ('url', 'status', 'headers', 'body', 'flags', 'request', 'certificate', 'ip_address', 'protocol', 'encoding')

一个由 str 对象组成的元组,包含类中所有公共属性的名称,这些属性也是 __init__() 方法的关键字参数。

当前由 Response.replace() 使用。

TextResponse 对象除了标准 Response 方法外,还支持以下方法:

jmespath(query)[source]

指向 TextResponse.selector.jmespath(query) 的快捷方式

response.jmespath('object.[*]')
xpath(query)[source]

指向 TextResponse.selector.xpath(query) 的快捷方式

response.xpath('//p')
css(query)[source]

指向 TextResponse.selector.css(query) 的快捷方式

response.css('p')
follow(url: str | Link | parsel.Selector, callback: CallbackT | None = None, method: str = 'GET', headers: Mapping[AnyStr, Any] | Iterable[tuple[AnyStr, Any]] | None = None, body: bytes | str | None = None, cookies: CookiesT | None = None, meta: dict[str, Any] | None = None, encoding: str | None = None, priority: int = 0, dont_filter: bool = False, errback: Callable[[Failure], Any] | None = None, cb_kwargs: dict[str, Any] | None = None, flags: list[str] | None = None) Request[source]

返回一个 Request 实例,用于跟踪一个链接 url。它接受与 Request.__init__() 方法相同的参数,但 url 不仅可以是绝对 URL,还可以是

  • 相对 URL

  • 一个 Link 对象,例如 Link Extractors 的结果

  • 一个 Selector 对象,用于 <link><a> 元素,例如 response.css('a.my_link')[0]

  • 一个属性 Selector(不是 SelectorList),例如 response.css('a::attr(href)')[0]response.xpath('//img/@src')[0]

参阅 创建请求的快捷方式 以获取用法示例。

follow_all(urls: Iterable[str | Link] | parsel.SelectorList | None = None, callback: CallbackT | None = None, method: str = 'GET', headers: Mapping[AnyStr, Any] | Iterable[tuple[AnyStr, Any]] | None = None, body: bytes | str | None = None, cookies: CookiesT | None = None, meta: dict[str, Any] | None = None, encoding: str | None = None, priority: int = 0, dont_filter: bool = False, errback: Callable[[Failure], Any] | None = None, cb_kwargs: dict[str, Any] | None = None, flags: list[str] | None = None, css: str | None = None, xpath: str | None = None) Iterable[Request][source]

一个生成器,用于生成 Request 实例以追踪 urls 中的所有链接。它接受与 Request__init__() 方法相同的参数,但每个 urls 元素不需要是绝对 URL,可以是以下任一类型

  • 相对 URL

  • 一个 Link 对象,例如 Link Extractors 的结果

  • 一个 Selector 对象,用于 <link><a> 元素,例如 response.css('a.my_link')[0]

  • 一个属性 Selector(不是 SelectorList),例如 response.css('a::attr(href)')[0]response.xpath('//img/@src')[0]

此外,接受 cssxpath 参数可在 follow_all() 方法内部执行链接提取(仅接受 urlscssxpath 中的一个参数)。

注意,当将 SelectorList 作为 urls 参数的实参传递,或使用 cssxpath 参数时,此方法不会为无法获取链接的选择器生成请求(例如,没有 href 属性的锚标签)。

json()[source]

2.2 版本新增。

将 JSON 文档反序列化为 Python 对象。

返回从反序列化 JSON 文档中获得的 Python 对象。结果会在首次调用后缓存。

urljoin(url)[source]

通过将 Response 的基本 URL 与可能的相对 URL 组合来构建绝对 URL。基本 URL 应从 <base> 标签中提取,如果没有此类标签,则使用 Response.url

HtmlResponse 对象

class scrapy.http.HtmlResponse(url[, ...])[source]

HtmlResponse 类是 TextResponse 的子类,通过查看 HTML meta http-equiv 属性来添加编码自动发现支持。参阅 TextResponse.encoding

XmlResponse 对象

class scrapy.http.XmlResponse(url[, ...])[source]

XmlResponse 类是 TextResponse 的子类,通过查看 XML 声明行来添加编码自动发现支持。参阅 TextResponse.encoding

JsonResponse 对象

class scrapy.http.JsonResponse(url[, ...])[source]

JsonResponse 类是 TextResponse 的子类,当响应在其 Content-Type 头部中具有 JSON MIME 类型时使用。