Python爬虫Scrapy(七)_Request_Response

本章将介绍Request与Response,更多内容请参考:Python学习指南
Request Request源码:
# 部分代码 class 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):self._encoding = encoding# this one has to be set first self.method = str(method).upper() self._set_url(url) self._set_body(body) assert isinstance(priority, int), "Request priority not an integer: %r" % priority self.priority = priorityassert callback or not errback, "Cannot use errback without a callback" self.callback = callback self.errback = errbackself.cookies = cookies or {} self.headers = Headers(headers or {}, encoding=encoding) self.dont_filter = dont_filterself._meta = dict(meta) if meta else None@property def meta(self): if self._meta is None: self._meta = {} return self._meta

其中,比较常用的参数:
url:就是需要请求,并进行下一步处理的url
callback:指定该请求返回的response,由哪个函数来处理。
method: 请求一般不需要指定,默认为GET方法,可设置为"GET"、"POST"、"PUT"等,且保证字符串大写。
headers: 请求时,包含的头文件。一般不需要,内容一般如下:
  • Host:media.readthedocs.org
  • User-Agent:Mozilla/5.0 (Window NT 6.2; WOW64; rv:33.0) Cecko/20100101 Firefox/33.0
  • Accept:text/css, /; q=0.1
  • Accept-Language:zh-cn,zh; q=0.8,en-us; q=0.5,en; q=0.3
  • Accept-Encoding:gzip,deflate
  • Referrer:http://scrapy-chs.readthedocs.org/zh_CN/0.24
  • Cookie:_ga=GA2.1612165614.14532342342
  • Connection:keep-alive
  • If-Modified-Since:Mon, 25 Aug 2015 21:59:35 GMT
  • Cache-Contro:max-age=0
meta:比较常用,在不同的请求之间传递数据使用的。字典dict型
"""
request_with_cookies = Request(
url="http://www.example.com",
cookies={'currency': 'USD', 'country': 'UY'},
meta={'dont_merge_cookies': True}
)
"""
encoding:使用默认的'utf-8'就行。
dont_filter:表明该请求不由调度器过滤。这是当你想使用多次执行相同的其你去,就忽略重复的过滤器。默认为False
errback:指定错误处理函数
Request.meta
Request.meata在不同请求之间传递数据使用的。
Request.meta属性可以包含任意的数据,但是Scrapy和它的内置扩展可以识别一些特殊的键。
  • dont_rediect:不重定向
  • dont_retry:不重试
  • handle_httpstatus_list
  • dont_merge_cookies:不合并cookie
  • cookiejar:使用cookiejar
  • rediect_urls:重定向连接
  • bindaddress:绑定ip地址
  • dont_obey_robotstxt:不遵循反爬虫协议
  • download_timeout:下载超时
Request的子类FormRequest FormRequest是Request的子类,一般用作表单数据提交。
class FormRequest(Request):def __init__(self, *args, **kwargs): formdata = https://www.it610.com/article/kwargs.pop('formdata', None) if formdata and kwargs.get('method') is None: kwargs['method'] = 'POST'super(FormRequest, self).__init__(*args, **kwargs)

FormRequest的构造:
class scrapy.http.FormRequest(url, [formdata,...])

FormRequest类除了有Request的功能,还提供了form_response的功能
def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=https://www.it610.com/article/None,clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs)

  • response:是指包含HTML表单的Response对象,该表单将用于预填充表单字段。
  • formname:如果给定,将使用form表单的name属性为该值的name属性的表单。
  • formid:如果给定,将使用form表单的id属性为该值的name属性的表单
  • formnumber:当响应包含多个表单时,要使用的表单的数量。 formnumber默认是0,表示使用第一个。
  • formdata:字段来覆盖表单数据。如果一个字段已经存在于响应
    元素中,那么它的值被在这个参数中传递的值覆盖。
  • formxpath:如果给定,将使用与XPath匹配的第一个表单。
  • clickdata:查找单击控件的属性。如果没有给出,表单数据将被提交模拟点击第一个可点击的元素。
  • dont_click:如果为True,表单数据将被提交而不需要单击任何元素。
Response
# 部分代码 class Response(object_ref): def __init__(self, url, status=200, headers=None, body='', flags=None, request=None): self.headers = Headers(headers or {}) self.status = int(status) self._set_body(body) self._set_url(url) self.request = request self.flags = [] if flags is None else list(flags)@property def meta(self): try: return self.request.meta except AttributeError: raise AttributeError("Response.meta not available, this response " \ "is not tied to any request")

大部分参数和上面的差不多:
status :响应的状态码 body :响应体 url :响应url headers:响应对象的响应报头 meta:为response.meta属性的初始值。如果给定的,字典将浅复制。

Response的子类
Response的继承关系
Response TextResponse HtmlResponse XmlResponse

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

TextResponse对象增加了编码能力的基础响应类,是指将只用于二进制数据,如图像、生硬或任何媒体文件。
TextResponse对象除了标准的Response对象外,还支持以下属性和方法:
  • encoding:
    与此响应编码的字符串。 通过尝试以下机制来解决编码问题:
    • 在构造函数编码参数中传递的编码
    • 在Content-Type HTTP头中声明的编码。如果这种编码是无效的(即未知的),它将被忽略,并尝试下一个解析机制。
    • 在响应正文中声明的编码。TextResponse类不提供任何特殊的功能。但是,HtmlResponse和XmlResponse类可以。
    • 通过查看响应主体来推断编码。 这是更脆弱的方法,但也是最后一个尝试。
  • selector : 使用响应作为目标的选择器实例。
  • ``body_as_unicode()` : 以unicode形式返回响应的主体。
  • xpath(query) : xpath解析
textresponse.selector.css('p')#也可以简写为:textresponse.css('p')

  • css(query) : :css解析,相当于BeautifulSoup4解析
textresponse.selector.css('p')#也可以简写为:textresponse.css('p')

HtmlResponse HtmlResponse类是TextResponse的一个子类,它通过查看HTML meta http-equiv属性来添加编码自动发现支持。
XmlResponse XmlResponse类是TextResponse的一个子类,它通过查看XML声明行来添加编码自动发现支持。
Response的
发送POST请求
  • 可以使用yield scrapy.FormRequest(url, formdata, callback)的方法发送POST请求。
  • 如果希望程序执行一开始就发送POST请求,可以重写Spider类的start_requests(self)方法,并且不再调用start_urls里的url。
class mySpider(scrapy.Spider): #start_utls = ['http://www.example d'] def start_requests(self): url = "http://www.renren.com/PLogin.do"#FormRequest是Scrapy发送POST请求的方法 yield scrapy.FormRequest( url = url, formdata = https://www.it610.com/article/{"email" : "xxxx@qq.com", "password":"xxxxxx"} callback = self.parse_page ) def parse_page(self, response): #do something

模拟登陆 使用FormRequest.form_response()方法模拟用户登陆
通常网站通过实现对某些表单字段(如数据或者登陆界面中的认证令牌等)的预填充。
使用Scrapy抓取网页时,如果想要预填充或重写像用户名、用户密码这些表单字段时,可以使用FormRequest.from_response()方法实现。
在Request中不存在formadata参数,所以无法使用提交表单的方式
下面是使用这种方法的爬虫例子:
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=https://www.it610.com/article/{'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.log("Login failed", level=log.ERROR) return# continue scraping with authenticated session...

Github爬虫案例参考:
#-*- coding:utf-8 -*- from scrapy import Spider, Request, FormRequestclass GithubLoginSpider(Spider): name = "github" allow_domains = ['github.com']#post登入必须的头字段 post_headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", "Referer" : "https://github.com", "Origin" : 'https://github.com', "Host":'github.com' }def start_requests(self): """ 执行spider请求 :return 返回一个Request对象,请求登陆的页面 """ return [Request(url="https://github.com/login", meta={"cookiejar":1}, callback = self.post_login, headers = self.post_headers)]def post_login(self, response): """ 登陆的页面请求成功后,解析响应的页面,获取登陆需要的标签信息 :param response :登陆接口返回的页面 """#github登陆上传必要的字段 utf8 = response.xpath('//form//input[@name="utf8"]/@value').extract()[0] authenticity_token = response.xpath('//form//input[@name="authenticity_token"]/@value').extract()[0] login = "xxxx@qq.com" password = "xxxxxx" commit = response.xpath('//form//input[@name="commit"]/@value').extract()[0]#发送FormRequest表单请求 return FormRequest.from_response(response=response, meta={"cookiejar":response.meta['cookiejar']}, formdata = https://www.it610.com/article/{"utf8" : utf8, "authenticity_token" :authenticity_token, "login" : login, "password" : password, "commit" : commit }, callback = self.after_login, headers = self.post_headers )def after_login(self, response): """ form表单请求成功后,请求登陆我的页面 :param response :return:返回一个响应 """ print(response.body) if response.status == 200: with open("my_github.html", "wb") as f: f.write(response.body)

禁用遵循robot协议,打开Cookie
ROBOTSTXT_OBEY = False COOKIE_ENABLED = True

【Python爬虫Scrapy(七)_Request_Response】启动爬虫
scrapy crawl github

参考:
  1. Scrapy框架学习(五)—-Request、Response介绍及模拟GitHub登录

    推荐阅读