4-5 Scrapy知识补充

  FormRequest

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

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

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。能够处理这种隐藏的表单。chrome

注意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])cookie

参数说明:scrapy

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

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

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

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

  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)

相关文章
相关标签/搜索