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 = priority

        assert callback or not errback, "Cannot use errback without a callback"
        self.callback = callback
        self.errback = errback

        self.cookies = cookies or {}
        self.headers = Headers(headers or {}, encoding=encoding)
        self.dont_filter = dont_filter

        self._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 = 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=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:字段来覆盖表单数据。如果一个字段已经存在于响应<form>元素中,那么它的值被在这个参数中传递的值覆盖。
  • 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 = {"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 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.log("Login failed", level=log.ERROR)
            return

        # continue scraping with authenticated session...

Github爬虫案例参考:

#-*- coding:utf-8 -*-
from scrapy import Spider, Request, FormRequest

class 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):
        """
            登陆的页面请求成功后,解析响应的页面,获取登陆需要的<input>标签信息
            :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 = {
                "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

启动爬虫

scrapy crawl github

参考:

  1. Scrapy框架学习(五)—-Request、Response介绍及模拟GitHub登录
    原文作者:小七奇奇
    原文地址: https://www.jianshu.com/p/60caee137a25
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞