Requests and Responses:http://doc.scrapy.org/en/latest/topics/request-response.html
Requests and Responses(中文版):https://scrapy-chs.readthedocs.io/zh_CN/latest/topics/request-response.html
请求 和 响应
通常,Request对象 在 爬虫程序中生成并传递到系统,直到它们到达下载程序,后者执行请求并返回一个 Response对象,该对象 返回到发出请求的爬虫程序。
上面一段话比较拗口,有 web 经验的同学,应该都了解的,不明白看下面的图大概理解下。
- 爬虫 -> Request:创建
- Request -> Response:获取下载数据
- Response -> 爬虫:数据
Request 和 Response 类 都有一些子类,它们添加基类中不需要的功能。这些在下面 的 请求子类 和 响应子类中描述。
Request objects
class scrapy.http.Request (url [, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback, flags] )
一个 Request 对象 表示一个 HTTP请求,它通常是在爬虫生成,并由下载执行,从而生成 Response 对象。
参数:
- url (string) – the URL of this request
- callback (callable) – the function that will be called with the response of this request (once its downloaded) as its first parameter. For more information see Passing additional data to callback functions below. If a Request doesn’t specify a callback, the spider’s
parse()
method will be used. Note that if exceptions are raised during processing, errback is called instead. - method (string) – the HTTP method of this request. Defaults to
'GET'
. - meta (dict) – the initial values for the
Request.meta
attribute. If given, the dict passed in this parameter will be shallow copied. - body (str or unicode) – the request body. If a
unicode
is passed, then it’s encoded tostr
using the encoding passed (which defaults toutf-8
). Ifbody
is not given, an empty string is stored. Regardless of the type of this argument, the final value stored will be astr
(neverunicode
orNone
). - headers (dict) – the headers of this request. The dict values can be strings (for single valued headers) or lists (for multi-valued headers). If
None
is passed as value, the HTTP header will not be sent at all. - cookies (dict or list) –
the request cookies. These can be sent in two forms.
- Using a dict:
request_with_cookies = Request(url="http://www.example.com",cookies={'currency': 'USD', 'country': 'UY'})
- Using a list of dicts:
request_with_cookies = Request(url="http://www.example.com",cookies=[{'name': 'currency','value': 'USD','domain': 'example.com','path': '/currency'}])
The latter form allows for customizing the
domain
andpath
attributes of the cookie. This is only useful if the cookies are saved for later requests.When some site returns cookies (in a response) those are stored in the cookies for that domain and will be sent again in future requests. That’s the typical behaviour of any regular web browser. However, if, for some reason, you want to avoid merging with existing cookies you can instruct Scrapy to do so by setting the
dont_merge_cookies
key to True in theRequest.meta
.Example of request without merging cookies:
request_with_cookies = Request(url="http://www.example.com",cookies={'currency': 'USD', 'country': 'UY'},meta={'dont_merge_cookies': True})
For more info see CookiesMiddleware.
- Using a dict:
- encoding (string) – the encoding of this request (defaults to
'utf-8'
). This encoding will be used to percent-encode the URL and to convert the body tostr
(if given asunicode
). - priority (int) – the priority of this request (defaults to
0
). The priority is used by the scheduler to define the order used to process requests. Requests with a higher priority value will execute earlier. Negative values are allowed in order to indicate relatively low-priority. - dont_filter (boolean) – indicates that this request should not be filtered by the scheduler. This is used when you want to perform an identical request multiple times, to ignore the duplicates filter. Use it with care, or you will get into crawling loops. Default to
False
. - errback (callable) – a function that will be called if any exception was raised while processing the request. This includes pages that failed with 404 HTTP errors and such. It receives a Twisted Failure instance as first parameter. For more information, see Using errbacks to catch exceptions in request processing below.
- flags (list) – Flags sent to the request, can be used for logging or similar purposes.
对应中文解释:
url(string)
- 此请求的网址。请记住,此属性包含转义的网址,因此它可能与构造函数中传递的网址不同。此属性为只读。更改请求 的 URL 可以使用 Request 的replace()
。callback(callable)
- 将使用此请求的响应(一旦下载)作为其第一个参数调用的函数。有关更多信息,请参阅下面的将附加数据传递给回调函数。如果请求没有指定回调,parse()将使用spider的 方法。请注意,如果在处理期间引发异常,则会调用errback。method(string)
- 此请求的HTTP方法。默认为'GET'。注意:必须保证是大写的。例如:"GET","POST","PUT"
等meta(dict)
- 属性的初始值Request.meta。如果给定,在此参数中传递的 dict 将被浅复制。包含此请求的任意元数据的字典。此dict对于新请求为空,通常由不同的Scrapy组件(扩展程序,中间件等)填充。因此,此dict中包含的数据取决于您启用的扩展。有关Scrapy识别的特殊元键列表,请参阅Request.meta特殊键。当使用copy()
或者replace()
克隆请求时,此 dict 是 浅复制 的 。在爬虫中可以通过 response.meta 属性访问。body(str或unicode)
- 请求体。即 包含请求正文的 str。此属性为只读。更改body
可以使用 Request 的replace()
。如果unicode传递了a,那么它被编码为 str使用传递的编码(默认为utf-8)。如果 body 没有给出,则存储一个空字符串。不管这个参数的类型,存储的最终值将是一个str(不会是unicode或None)。headers(dict)
- 这个请求的头。dict 值可以是字符串(对于单值标头)或列表(对于多值标头)。如果 None作为值传递,则不会发送HTTP头。cookie(dict或list)
- 请求cookie。这些可以以两种形式发送encoding(string)
- 此请求的编码(默认为'utf-8')。此编码将用于对URL进行百分比编码,并将正文转换为str(如果给定unicode)。priority(int)
- 此请求的优先级(默认为0)。调度器使用优先级来定义用于处理请求的顺序。具有较高优先级值的请求将较早执行。允许负值以指示相对低优先级。dont_filter(boolean)
- 表示此请求不应由调度程序过滤。当您想要多次执行相同的请求时忽略重复过滤器时使用。小心使用它,或者你会进入爬行循环。默认为False。-
errback(callable)
- 如果在处理请求时引发任何异常,将调用的函数。这包括失败的404 HTTP错误等页面。它接收一个Twisted Failure实例作为第一个参数。有关更多信息,请参阅使用errbacks在请求处理中捕获异常。
-
copy()方法
返回一个新的请求,它是这个请求的副本。另请参见: 将附加数据传递到回调函数。 -
replace([url, method, headers, body, cookies, meta, encoding, dont_filter, callback, errback])
返回具有相同成员的Request对象,但通过指定的任何关键字参数赋予新值的成员除外。该属性Request.meta是默认复制(除非新的值在给定的meta参数)。另请参见 将附加数据传递给回调函数
repalce() 方法使用:首先看 下 这个方法在源码中的定义(scrapy/http/request/__init__.py):
"""
This module implements the Request class which is used to represent HTTP
requests in Scrapy.See documentation in docs/topics/request-response.rst
"""
import six
from w3lib.url import safe_url_stringfrom scrapy.http.headers import Headers
from scrapy.utils.python import to_bytes
from scrapy.utils.trackref import object_ref
from scrapy.utils.url import escape_ajax
from scrapy.http.common import obsolete_setterclass Request(object_ref):def __init__(self, url, callback=None, method='GET', headers=None, body=None,cookies=None, meta=None, encoding='utf-8', priority=0,dont_filter=False, errback=None, flags=None):self._encoding = encoding # this one has to be set firstself.method = str(method).upper()self._set_url(url)self._set_body(body)assert isinstance(priority, int), "Request priority not an integer: %r" % priorityself.priority = priorityif callback is not None and not callable(callback):raise TypeError('callback must be a callable, got %s' % type(callback).__name__)if errback is not None and not callable(errback):raise TypeError('errback must be a callable, got %s' % type(errback).__name__)assert callback or not errback, "Cannot use errback without a callback"self.callback = callbackself.errback = errbackself.cookies = cookies or {}self.headers = Headers(headers or {}, encoding=encoding)self.dont_filter = dont_filterself._meta = dict(meta) if meta else Noneself.flags = [] if flags is None else list(flags)@propertydef meta(self):if self._meta is None:self._meta = {}return self._metadef _get_url(self):return self._urldef _set_url(self, url):if not isinstance(url, six.string_types):raise TypeError('Request url must be str or unicode, got %s:' % type(url).__name__)s = safe_url_string(url, self.encoding)self._url = escape_ajax(s)if ':' not in self._url:raise ValueError('Missing scheme in request url: %s' % self._url)url = property(_get_url, obsolete_setter(_set_url, 'url'))def _get_body(self):return self._bodydef _set_body(self, body):if body is None:self._body = b''else:self._body = to_bytes(body, self.encoding)body = property(_get_body, obsolete_setter(_set_body, 'body'))@propertydef encoding(self):return self._encodingdef __str__(self):return "<%s %s>" % (self.method, self.url)__repr__ = __str__def copy(self):"""Return a copy of this Request"""return self.replace()def replace(self, *args, **kwargs):"""Create a new Request with the same attributes except for thosegiven new values."""for x in ['url', 'method', 'headers', 'body', 'cookies', 'meta', 'flags','encoding', 'priority', 'dont_filter', 'callback', 'errback']:kwargs.setdefault(x, getattr(self, x))cls = kwargs.pop('cls', self.__class__)return cls(*args, **kwargs)
replace() 方法 返回一个 类 的 实例,需要一个变量来保存这个类 实例。所以使用方式如下:
if __name__ == '__main__':from scrapy.http.request import Requestr = Request(url='https://www.baidu.com')r_1 = r.replace(url="https://www.google.com")print('r_1.url : {0}'.format(r_1.url))print('r_1.method : {0}'.format(r_1.method))r_2 = r.replace(method='post')print('r_2.url : {0}'.format(r_2.url))print('r_2.method : {0}'.format(r_2.method))r._set_url('http://www.sina.com')print('r.url : {0}'.format(r.url))print('r.method : {0}'.format(r.method))
运行结果截图:
将 附加数据 传递 给 回调函数
也就是 从 request 中传递数据 到 response
请求的回调是当下载该请求的响应时将被调用的函数。将使用下载的Response对象作为其第一个参数来调用回调函数。
Example:
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.htmlself.logger.info("Visited %s", response.url)
在某些情况下,您可能有兴趣向这些回调函数传递参数,以便稍后在第二个回调中接收参数。您可以使用该Request.meta属性。
以下是使用此机制传递项目以填充来自不同页面的不同字段的示例:
def parse_page1(self, response):item = MyItem()item['main_url'] = response.urlrequest = scrapy.Request("http://www.example.com/some_page.html",callback=self.parse_page2)request.meta['item'] = itemyield requestdef parse_page2(self, response):item = response.meta['item']item['other_url'] = response.urlyield item
使用 errbacks 在请求处理中捕获异常
请求的 errback 是在处理异常时被调用的函数。
它接收一个Twisted Failure实例作为第一个参数,并可用于跟踪连接建立超时,DNS错误等。
这里有一个 示例爬虫 记录所有错误,并捕获一些特定的错误,如果需要:
import scrapyfrom scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutErrorclass 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 failuresself.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 responseresponse = failure.value.responseself.logger.error('HttpError on %s', response.url)elif failure.check(DNSLookupError):# this is the original requestrequest = failure.requestself.logger.error('DNSLookupError on %s', request.url)elif failure.check(TimeoutError, TCPTimedOutError):request = failure.requestself.logger.error('TimeoutError on %s', request.url)
Request.meta 特殊键
该 Request.meta
属性可以包含任何任意数据,但有一些特殊的键由 Scrapy 及其内置扩展识别。
那些是:
dont_redirect
dont_retry
handle_httpstatus_list
handle_httpstatus_all
dont_merge_cookies(参见cookies构造函数的Request参数)
cookiejar
dont_cache
redirect_urls
bindaddress
dont_obey_robotstxt
download_timeout
download_maxsize
download_latency
proxy
bindaddress:用于执行请求的出站IP地址的IP。
download_timeout:下载器在超时前等待的时间量(以秒为单位)。参见:DOWNLOAD_TIMEOUT
。
download_latency:自请求已启动以来,用于获取响应的时间量,即通过网络发送的HTTP消息。此元键仅在响应已下载时可用。虽然大多数其他元键用于控制Scrapy行为,但这应该是只读的。
Request (请求) 的 subclasses(子类)
Here is the list of built-in Request
subclasses. You can also subclass it to implement your own custom functionality.
这是 Scrapy 框架中 Request 类 的 内建 subclasses(子类) 列表。你也可以 通过继承来实现它的一个子类,用来实现啊你自己自定的功能
FormRequest objects
FormRequest类 扩展了 Request 具有处理HTML表单的功能的基础。它使用lxml.html表单 从 Response对象 的 表单数据 预填充 表单字段。
FormRequest
class scrapy.http.
FormRequest
(url [, formdata, ...])
FormRequest
类 增加了新 的构造函数的 参数。其余的参数与 Request
类 相同,这里没有记录。
- 参数:formdata(元组的dict或iterable) - 是一个包含HTML Form数据的字典(或(key,value)元组的迭代),它将被url编码并分配给请求的主体。
from_response
FormRequest
对象 添加下面的方法到 标准的 Request 对象中:
classmethod from_response
(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])
Returns a new FormRequest
object with its form field values pre-populated with those found in the HTML <form>
element contained in the given response. For an example see Using FormRequest.from_response() to simulate a user login.
返回一个新 FormRequest
对象,其中它的 form(表单) 字段值 已预先设置,用在给定的 Response 对象 中 包含的 HTML 中 发现的 HTML <form> 元素 来 填充 字段值()。即 根据 response找到HTML的<from>元素,以此来填充给定的form字段值,并返回一个新的FormRequest对象。
有关示例,请参阅 使用FormRequest.from_response()来模拟用户登录。
The policy is to automatically simulate a click, by default, on any form control that looks clickable, like a <input type="submit">
. Even though this is quite convenient, and often the desired behaviour, sometimes it can cause problems which could be hard to debug. For example, when working with forms that are filled and/or submitted using javascript, the default from_response()
behaviour may not be the most appropriate. To disable this behaviour you can set the dont_click
argument to True
. Also, if you want to change the control clicked (instead of disabling it) you can also use the clickdata
argument.
参数:
- response (
Response
object) – the response containing a HTML form which will be used to pre-populate the form fields - formname (string) – if given, the form with name attribute set to this value will be used.
- formid (string) – if given, the form with id attribute set to this value will be used.
- formxpath (string) – if given, the first form that matches the xpath will be used.
- formcss (string) – if given, the first form that matches the css selector will be used.
- formnumber (integer) – the number of form to use, when the response contains multiple forms. The first one (and also the default) is
0
. - formdata (dict) – fields to override in the form data. If a field was already present in the response
<form>
element, its value is overridden by the one passed in this parameter. If a value passed in this parameter isNone
, the field will not be included in the request, even if it was present in the response<form>
element. - clickdata (dict) – attributes to lookup the control clicked. If it’s not given, the form data will be submitted simulating a click on the first clickable element. In addition to html attributes, the control can be identified by its zero-based index relative to other submittable inputs inside the form, via the
nr
attribute. - dont_click (boolean) – If True, the form data will be submitted without clicking in any element.
参数对应中文解释:
- response(Responseobject) - 包含将用于预填充表单字段的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,表单数据将在不点击任何元素的情况下提交。
Request 用法 示例
使用 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 scrapyclass 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 onif "authentication failed" in response.body:self.logger.error("Login failed")return# continue scraping with authenticated session...
Response 对象
class scrapy.http.
Response
(url [, status=200, headers=None, body=b'', flags=None, request=None])
一个 Response对象 表示 一个 HTTP响应,它通常是由下载器下载,并供给到爬虫进行处理。
参数:
- url (string) – the URL of this response
- status (integer) – the HTTP status of the response. Defaults to
200
. - headers (dict) – the headers of this response. The dict values can be strings (for single valued headers) or lists (for multi-valued headers).
- body (bytes) – the response body. To access the decoded text as str (unicode in Python 2) you can use
response.text
from an encoding-aware Response subclass, such asTextResponse
. - flags (list) – is a list containing the initial values for the
Response.flags
attribute. If given, the list will be shallow copied. - request (
Request
object) – the initial value of theResponse.request
attribute. This represents theRequest
that generated this response.
参数 对应中文解释:
- url(string) - 此响应的 URL
- status(integer) - 响应的 HTTP 状态。默认为 200。
- headers(dict) - 这个响应的头。dict 值可以是字符串(对于单值标头)或列表(对于多值标头)。
- body(str) - 响应体。它必须是 str,而不是 unicode,除非你使用一个编码感知 响应子类,如
TextResponse
。 - flags(list) - 是一个包含属性初始值的
Response.flags
列表。如果给定,列表将被浅复制。 - request(Requestobject) - 属性的初始值
Response.request
。这代表Request生成此响应。
url
包含响应的URL的字符串。此属性为只读。To change the URL of a Response use replace()
.
status
表示 响应的HTTP状态的整数。示例:200, 404。
headers
包含响应标题的类字典对象。可以使用get()返回具有指定名称的第一个标头值或getlist()返回具有指定名称的所有标头值来访问值。例如,此调用会为您提供标题中的所有Cookie:
response.headers.getlist('Set-Cookie')
body
Response 的 body。记住 Response.body 总是一个字节对象。如果你想 unicode 版本使用 TextResponse.text(只在TextResponse 和子类中可用)。此属性为只读。更改响应使用的主体 replace()。
request
生成 response 的 Request
object。在响应和请求通过所有 下载中间件 后,此属性在 Scrapy 引擎 中分配。特别地,这意味着:
- HTTP 重定向将导致将原始请求(重定向之前的URL)分配给重定向响应(重定向后具有最终URL)。
- Response.request.url 并不总是等于 Response.url
- 此属性仅在爬虫程序代码和 Spider Middleware中可用,但不能在Downloader Middleware中使用(尽管您有通过其他方式可用的请求)和处理程序response_downloaded。
meta
一个快捷方式 对于 Request.meta 的属性 对于 Response.request对象(即 self.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)
follow (url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding='utf-8', priority=0, dont_filter=False, errback=None)
Return a Request
instance to follow a link url
. It accepts the same arguments as Request.__init__
method, but url
can be a relative URL or a scrapy.link.Link
object, not only an absolute URL.
TextResponse
provides a follow()
method which supports selectors in addition to absolute/relative URLs and Link objects.
Response(响应) 的 subclasses(子类)
这是 Scrapy 框架中 Response类 的 内建 subclasses(子类) 列表。你也可以 通过继承来实现它的一个子类,用来实现啊你自己自定的功能
TextResponse对象
class scrapy.http.
TextResponse
(url [, encoding[, ...]])
TextResponse 对象 向基类Response类添加编码能力 ,这意味着仅用于二进制数据,例如图像,声音或任何媒体文件。
TextResponse 对象 支持一个新的构造函数参数,除了基础Response对象。其余的功能与Response类相同,这里没有记录。
参数: encoding(string) - 是一个字符串,包含用于此响应的编码。如果你创建一个TextResponse具有unicode主体的对象,它将使用这个编码进行编码(记住body属性总是一个字符串)。如果encoding是None(默认值),则将在响应标头和正文中查找编码。
TextResponse除了标准对象之外,对象还支持以下属性Response
text
响应体,unicode 编码。
同样 response.body.decode(response.encoding)
,但结果是在第一次调用后缓存,因此您可以访问 response.text
多次,无需额外的开销。
encoding
包含此响应的编码的字符串。编码通过尝试以下机制按顺序解决:
- 在构造函数编码参数中传递的编码
- 在Content-Type HTTP头中声明的编码。如果此编码无效(即未知),则会被忽略,并尝试下一个解析机制。
- 在响应主体中声明的编码。TextResponse类不提供任何特殊功能。然而, HtmlResponse和XmlResponse类做。
- 通过查看响应体来推断的编码。这是更脆弱的方法,但也是最后一个尝试。
selector
一个Selector使用响应为目标实例。选择器在第一次访问时被延迟实例化。TextResponse对象除了标准对象外还支持以下方法Response:
xpath(查询)
快捷方式 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。