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)

相關文章
相關標籤/搜索