• 4-5 Scrapy知识补充


      FormRequest

      FormRequest类是专门用来处理HTML表单的,同时对隐藏的表单处理也很方便。适合用来完成登录操作。

      类原型:class scrapy.http.FormRequest(url[, formdata, ...])其构造参数formdata可以是字典形式,也可以是(key, value)元组形式。代表需提交的表单数据。

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

       通常网站通过<inputtype=“hidden”>实现对某些表单字段(如数据或是登录界面中的认证令牌等)的预填充,如前知乎的 _xsrf参数。FormRequest类提供了一个类方法from_response。可以处理这种隐藏的表单。

    注意html知识补充:所有需要登陆的表单字段都会在html中的form标签中找到,其中需要输入的在form标签的后辈节点input标签中,然后输出的name和value会在input标签中的name属性和value属性中找到。from_response正式利用此到form标签中的后辈节点寻找input标签然后将其name属性为key和value属性为value收集在一起构造(key, value)作为添加进入formdata的值。

                       

       from_response(response[, formname=None, formnumber=0, formdata=None, formxpath=None, clickdata=None])

    参数说明:

      response:一个包含HTML表单的响应页面。

      formname(string):如果不为None,表单中的name属性将会被设定为这个值。

      formnumber(int):当响应页面中包含多个HTML表单时,本参数用来指定使用第几个表单,第一个表单数字为0。

      formdata(dict):本参数用来填充表单中属性的值。如果其中一个属性的值在响应页面中已经被预填充,但formdata中也指定了这个属性的值,将会把预填充的值覆盖掉。

      formxpath(string):如果页面中有多个HTML表单,可以用xpath表达式定位页面中的表单,第一个被匹配的将会被操作。

      用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

     BrowserCooCookieJarkiesMiddleware

      源码分析:

        首先构造方法中有个 self.jars = defaultdict(CookieJar) 这涉及到defaultdict()的使用。

    defaultdict()方法和字典的用法大同小异,最大的区别是当defaultdict()可以接受一个函数或者是类作为参数,然后如果只指定defaultdict的一个键,那么该键的值会被默认的参数(如果是函数则为函数返回值,如果为类则为最基础类)填充。看实例:

    from collections import defaultdict
    a = defaultdict(list)
    b = a['frank']
    print(b)
    
    输出结果:
    []

    因为defaultdict参数为list,则当指定一个键frank的时候,就会设置该frank的值为一个最基础的列表,即[], 将其值赋给b所以b为[] 甚至可以不指定值给b,直接指定一个键,然后该defaultdict就会变成{'frank': []}

    的形式。

    from collections import defaultdict
    a = defaultdict(list)
    a['frank']
    print(a)
    
    输出结果:
    defaultdict(<class 'list'>, {'frank': []})

       回到BrowserCookiesMiddleware类,中构造方法,self.jars = defaultdict(CookieJar) 意思即为类的jars变量创建一个CookieJar对象。 回到CookieJar源码,可以看到该类有一个重要的方法,set_cookie(),该防范出入一个cookie对象作为参数,然后将其添加到CookieJar中。于是根据以上我们可以自己设置自己的 BrowserCooCookieJarkiesMiddleware 来为Request设置cookie

    import browsercookie
    from scrapy.downloadermiddlewares.cookies import 
    
    CookiesMiddleware
    class MyCookie(CookiesMiddleware):
        def __init__(self, debug=False):
            super().__init__(debug)
            self.load_browser_cookies()
        def load_browser_cookies(self):
            # 加载Chrome 浏览器中的Cookie
            jar = self.jars['chrome']
            chrome_cookiejar = browsercookie.chrome()
            for cookie in chrome_cookiejar:
                jar.set_cookie(cookie)

      分析:

    • self.load_browser_cookies方法加载浏览器Cookie 。
    • 在load_browser_cookies方法中,使用self.jars['chrome']和self.jars['firefox']从默认字典中获得两个CookieJar对象。
    • 然后调用browsercookie的chrome和firefox方法,分别获取两个浏览器中的Cookie,将它们填入各自的CookieJar对象中。

     Scrapy & bloomfilter

       scrapy 自带的去重方案是set()与hashlib.sha1()完成的。源码如下:

        def __init__(self, path=None, debug=False):
            self.file = None
            self.fingerprints = set()
            self.logdupes = True
            self.debug = debug
            self.logger = logging.getLogger(__name__)
            if path:
                self.file = open(os.path.join(path, 'requests.seen'), 'a+')
                self.file.seek(0)
                self.fingerprints.update(x.rstrip() for x in self.file)

    request_fingerprint方法实现过滤的,将Request指纹添加到set()中。部分源码如下:

    def request_fingerprint(request, include_headers=None):
        if include_headers:
            include_headers = tuple(to_bytes(h.lower())
                                     for h in sorted(include_headers))
        cache = _fingerprint_cache.setdefault(request, {})
        if include_headers not in cache:
            fp = hashlib.sha1()
            fp.update(to_bytes(request.method))
            fp.update(to_bytes(canonicalize_url(request.url)))
            fp.update(request.body or b'')
            if include_headers:
                for hdr in include_headers:
                    if hdr in request.headers:
                        fp.update(hdr)
                        for v in request.headers.getlist(hdr):
                            fp.update(v)
            cache[include_headers] = fp.hexdigest()
        return cache[include_headers]

     去重指纹为sha1(method+url+body+header)

  • 相关阅读:
    【Android學習專題】数据存储篇:SharedPreferences/Files/SDCard
    【My Sft】彩色图像分析软件V1.0.1.0
    【流媒體】Android 实时视频采集—Camera预览采集
    【流媒體】 Android 实时视频编码—H.264硬编码
    【资料整理】一些英语面试题整理
    【C/C++语法外功】sizeof
    【My Project】开关稳压电源第八届索尼杯全国大学生电子设计竞赛(2007)
    【Android學習專題】網絡通信篇:Socket TCP(简易聊天室)
    【Android學習專題】多媒體篇:MediaRecoder 实现录像机
    【流媒體】Android 实时视频采集—MediaRecoder录制
  • 原文地址:https://www.cnblogs.com/yc3110/p/10809572.html
Copyright © 2020-2023  润新知