Skip to main content

请求和响应

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

通常,Request 对象在蜘蛛程序中生成,并传递到系统,直到它们到达下载程序,该程序执行请求并返回 Response 对象,该对象返回到发出请求的蜘蛛程序。

RequestResponse 类都具有添加基类中不需要的功能的子类。这些在下面的 请求子类响应子类 中描述。

请求对象

class scrapy.http.Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback])

Request 对象表示HTTP请求,它通常在Spider中生成并由下载程序执行,从而生成 Response

参数:
  • url (string) – 此请求的URL
  • callback (callable) – 将使用此请求的响应(一旦其下载)作为其第一个参数调用的函数。有关更多信息,请参阅下面的 将附加数据传递给回调函数。如果请求没有指定回调,将使用蜘蛛的 parse() 方法。请注意,如果在处理期间引发异常,则会调用errback。
  • method (string) – 此请求的HTTP方法。默认为 'GET'
  • meta (dict) – Request.meta 属性的初始值。如果给定的,在这个参数传递的字典将是浅复制。
  • body (str or unicode) – 请求体。如果传递 unicode,则使用传递的 encoding (其默认为 utf-8)将其编码到 str。如果未给出 body,则存储一个空字符串。无论此参数的类型如何,存储的最终值将是 str (从不是 unicodeNone)。
  • headers (dict) – 此请求的标头。 dict值可以是字符串(对于单值标头)或列表(对于多值标头)。如果 None 作为值传递,则不会发送HTTP头。
  • cookies (dict or list) – 请求cookie。这些可以以两种形式发送。 1. 使用dict:: request_with_cookies = Request(url=”http://www.example.com”, cookies={‘currency’: ‘USD’, ‘country’: ‘UY’}) 2. 使用一个列表:: request_with_cookies = Request(url=”http://www.example.com”, cookies=[{‘name’: ‘currency’, ‘value’: ‘USD’, ‘domain’: ‘example.com’, ‘path’: ‘/currency’}]) 后者允许定制cookie的 domainpath 属性。这只有在保存Cookie用于以后的请求时才有用。当某些网站返回Cookie(在响应中)时,这些Cookie会存储在该域的Cookie中,并在将来的请求中再次发送。这是任何常规网络浏览器的典型行为。但是,如果由于某些原因,您想要避免与现有Cookie合并,您可以指示Scrapy这样做,方法是在 Request.meta 中将 dont_merge_cookies 键设置为True。不合并Cookie的请求示例:: request_with_cookies = Request(url=”http://www.example.com”, cookies={‘currency’: ‘USD’, ‘country’: ‘UY’}, meta={‘dont_merge_cookies’: True}) 更多信息见 Cookie中间件
  • encoding (string) – 此请求的编码(默认为 'utf-8')。此编码将用于对URL进行百分比编码,并将正文转换为 str (如果以 unicode 形式提供)。
  • priority (int) – 此请求的优先级(默认为 0)。调度器使用优先级来定义用于处理请求的顺序。具有较高优先级值的请求将较早执行。允许负值以指示相对低优先级。
  • dont_filter (boolean) – 表示此请求不应由调度程序过滤。当您想要多次执行相同的请求时忽略重复过滤器时使用。小心使用它,或者你会进入爬行循环。默认为 False
  • errback (callable) – 如果在处理请求时引发任何异常,将调用的函数。这包括失败的404 HTTP错误等页面。它接收 Twisted Failure 实例作为第一个参数。有关详细信息,请参阅下面的 使用errbacks在请求处理中捕获异常
url

包含此请求的网址的字符串。请记住,此属性包含转义的网址,因此它可能与构造函数中传递的网址不同。

此属性为只读。更改请求的URL使用 replace()

method

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

headers

包含请求标头的类似字典的对象。

body

包含请求正文的str。

此属性为只读。更改请求的主体使用 replace()

meta

包含此请求的任意元数据的字典。此dict对于新请求为空,通常由不同的Scrapy组件(扩展程序,中间件等)填充。因此,此dict中包含的数据取决于您启用的扩展。

有关Scrapy识别的特殊元键列表,请参阅 Request.meta特殊键

当使用 copy()replace() 方法克隆请求时,此dict是 shallow copied,也可以在您的蜘蛛中从 response.meta 属性访问。

copy()

返回一个新的请求,它是这个请求的副本。参见:将附加数据传递给回调函数

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

返回具有相同成员的Request对象,但通过指定的任何关键字参数赋予新值的成员除外。默认情况下复制属性 Request.meta (除非在 meta 参数中给出新值)。参见 将附加数据传递给回调函数

将附加数据传递给回调函数

请求的回调是当下载该请求的响应时将被调用的函数。将使用下载的 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.meta 属性。

下面是一个使用此机制传递项目以填充不同页面的不同字段的示例:

def parse_page1(self, response):
    item = MyItem()
    item['main_url'] = response.url
    request = scrapy.Request("http://www.example.com/some_page.html",
                             callback=self.parse_page2)
    request.meta['item'] = item
    yield request

def parse_page2(self, response):
    item = response.meta['item']
    item['other_url'] = response.url
    yield item

使用errbacks在请求处理中捕获异常

请求的errback是在处理异常时被调用的函数。

它接收 Twisted 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
        "http://www.httphttpbinbin.org/",       # DNS error expected
    ]

    def start_requests(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)

Request.meta特殊键

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

那些是:

bindaddress

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

download_timeout

下载器在超时前等待的时间量(以秒为单位)。参见:DOWNLOAD_TIMEOUT

download_latency

自请求已启动以来,用于获取响应的时间量,即通过网络发送的HTTP消息。此元键仅在响应已下载时可用。虽然大多数其他元键用于控制Scrapy行为,但这应该是只读的。

请求子类

这里是内置的 Request 子类的列表。您还可以将其子类化以实现您自己的自定义功能。

FormRequest对象

FormRequest类扩展了具有处理HTML表单的功能的基本 Request。它使用 lxml.html forms 通过 Response 对象的表单数据预填充表单字段。

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

FormRequest 类向构造函数添加一个新参数。其余的参数与 Request 类相同,这里没有记录。

参数:formdata (dict or iterable of tuples) – 是一个包含HTML表单数据的字典(或((key,value)元组的迭代),它将被url编码并分配给请求的主体。

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

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 参数。

参数:
  • response (Response object) – 该响应包含将用于预填充表单字段的HTML表单
  • formname (string) – 如果给定,将使用具有设置为此值的name属性的形式。
  • formid (string) – 如果给定,将使用具有设置为此值的id属性的形式。
  • formxpath (string) – 如果给定,将使用与xpath匹配的第一个表单。
  • formcss (string) – 如果给定,将使用与css选择器匹配的第一个表单。
  • formnumber (integer) – 要使用的表单的数量,当响应包含多个表单时。第一个(也是默认值)是 0
  • formdata (dict) – 字段在表单数据中覆盖。如果响应 <form> 元素中已存在字段,则其值将被在此参数中传递的值覆盖。
  • clickdata (dict) – 属性来查找单击的控件。如果没有提供,表单数据将被提交,模拟第一个可点击元素的点击。除了html属性,控件可以通过其相对于窗体中其他提交表输入的基于零的索引,通过 nr 属性来标识。
  • dont_click (boolean) – 如果为True,表单数据将在不点击任何元素的情况下提交。

此类方法的其他参数直接传递到 FormRequest 构造函数。

0.10.3 新版功能: formname 参数。

0.17 新版功能: formxpath 参数。

1.1.0 新版功能: formcss 参数。

1.1.0 新版功能: formid 参数。

请求使用示例

使用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

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):
        # check login succeed before going on
        if "authentication failed" in response.body:
            self.logger.error("Login failed")
            return

        # continue scraping with authenticated session...

响应对象

class scrapy.http.Response(url[, status=200, headers=None, body=b'', flags=None, request=None])

Response 对象表示HTTP响应,通常由Downloader下载并馈送给Spiders进行处理。

参数:
  • url (string) – 此响应的URL
  • status (integer) – 响应的HTTP状态。默认为 200
  • headers (dict) – 此响应的标题。 dict值可以是字符串(对于单值标头)或列表(对于多值标头)。
  • body (str) – 响应体。它必须是str,而不是unicode,除非你使用编码感知的 响应子类,如 TextResponse
  • flags (list) – 是包含 Response.flags 属性的初始值的列表。如果给定,列表将被浅复制。
  • request (Request object) – Response.request 属性的初始值。这表示产生此响应的 Request
url

包含响应的URL的字符串。

此属性为只读。要更改响应的URL,请使用 replace()

status

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

headers

包含响应标题的类字典对象。可以使用 get() 访问值以返回具有指定名称的第一个标头值或 getlist(),以返回具有指定名称的所有标头值。例如,此调用将为您提供标题中的所有Cookie:

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

本回复的正文。记住Response.body总是一个字节对象。如果你想unicode版本使用 TextResponse.text (只在 TextResponse 和子类中可用)。

此属性为只读。要更改响应的主体,请使用 replace()

request

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

  • HTTP重定向将导致将原始请求(重定向之前的URL)分配给重定向响应(重定向后具有最终URL)。

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

  • 此属性仅在蜘蛛程序代码和 蜘蛛中间件 中可用,但不能在下载中间件(虽然您有通过其他方式可用的请求)和 response_downloaded 信号的处理程序。

meta

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

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

参见

Request.meta 属性

flags

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

copy()

返回一个新的响应,它是此响应的副本。

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

返回具有相同成员的Response对象,但通过指定的任何关键字参数赋予新值的成员除外。默认情况下将复制属性 Response.meta

urljoin(url)

通过将响应的 url 与可能的相对URL组合构造绝对url。

这是 urlparse.urljoin 的一个包装,它只是一个别名来进行这个调用:

urlparse.urljoin(response.url, url)

响应子类

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

TextResponse对象

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

TextResponse 对象向基本 Response 类添加编码能力,这意味着仅用于二进制数据,例如图像,声音或任何媒体文件。

除了基本的 Response 对象之外,TextResponse 对象还支持新的构造函数参数。其余功能与 Response 类相同,在此不作说明。

参数:encoding (string) – 是一个字符串,其中包含用于此响应的编码。如果您创建一个具有unicode主体的 TextResponse 对象,它将使用此编码进行编码(记住body属性总是一个字符串)。如果 encodingNone (默认值),则将在响应头和正文中查找编码。

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

text

响应体,如unicode。

response.body.decode(response.encoding) 相同,但是结果在第一次调用后缓存,因此您可以多次访问 response.text,而无需额外的开销。

注解

unicode(response.body) 不是将响应主体转换为unicode的正确方法:您将使用系统默认编码(通常为 ascii)而不是响应编码。

encoding

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

  1. 在构造函数 encoding 参数中传递的编码

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

  3. 在响应主体中声明的编码。 TextResponse类不提供任何特殊功能。然而,HtmlResponseXmlResponse 类做的。

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

selector

使用响应作为目标的 Selector 实例。选择器在第一次访问时被延迟实例化。

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

xpath(query)

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

response.xpath('//p')
css(query)

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

response.css('p')
body_as_unicode()

text 相同,但可用作方法。保留此方法以实现向后兼容;请优先 response.text

HtmlResponse对象

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

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

XmlResponse对象

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

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