Scrapy源碼注解--CookiesMiddleware


class CookiesMiddleware(object):
    """
    中間件在Scrapy啟動時實例化.其中jars屬性是一個默認值為CookieJar對象的dict.
    該中間件追蹤web server發送的cookie,保存在jars中,並在之后的request中發送回去,
    類似瀏覽器的行為.

    CookiesMiddleware還用於實現單Spider多cookie.通過在Request meta中添加cookiejar來支持單
    spider追蹤多cookie session.默認情況下其使用一個cookie jar(session),不過您可以傳遞一個
    標示符來使用多個。
    例如:
    for i, url in enumerate(urls):
        yield scrapy.Request("http://www.example.com", meta={'cookiejar': i},callback=self.parse_page)
    注意:meta中的cookiejar僅存儲了cookiejar的標識,真是的cookiejar存儲在CookiesMiddleware實
    例的jars屬性中
    """
    def __init__(self, debug=False):
        self.jars = defaultdict(CookieJar)
        self.debug = debug

    @classmethod
    def from_crawler(cls, crawler):
        # COOKIES_ENABLED默認值為True,是否啟用CookiesMiddleware
        # COOKIES_DEBUG默認值為False,如果啟用,Scrapy將記錄所有在request(Cookie 請求頭)發
        # 送的cookies及response接收到的cookies(Set-Cookie 接收頭)。
        if not crawler.settings.getbool('COOKIES_ENABLED'):
            raise NotConfigured
        return cls(crawler.settings.getbool('COOKIES_DEBUG'))

    def process_request(self, request, spider):
        if request.meta.get('dont_merge_cookies', False):
            return
        # 如果在request meta中使用了cookiejar, cookiejarkey為對應的標識.
        # 否則cookiejarkey為None
        cookiejarkey = request.meta.get("cookiejar")
        # 第一次執行jars會為每個key產生一個默認值cookiejar對象.默認為{None: cookiejar}
        jar = self.jars[cookiejarkey]    
       # 見下面_get_request_cookies()方法
        cookies = self._get_request_cookies(jar, request)
        for cookie in cookies:
            jar.set_cookie_if_ok(cookie, request)
        # set Cookie header
        request.headers.pop('Cookie', None)
        # 將cookie加入到request的headers中
        jar.add_cookie_header(request)
        self._debug_cookie(request, spider)

    def process_response(self, request, response, spider):
        if request.meta.get('dont_merge_cookies', False):
            return response
        # extract cookies from Set-Cookie and drop invalid/expired cookies
        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
       # 在請求允許的情況下(?),從response中提取cookie並入當前的cookiejar
        jar.extract_cookies(response, request)
        self._debug_set_cookie(response, spider)

        return response
    ...
    ...

    def _format_cookie(self, cookie):
        # 對以字典或字典的列表的形式傳入的cookie進行格式化
        cookie_str = '%s=%s' % (cookie['name'], cookie['value'])

        if cookie.get('path', None):
            cookie_str += '; Path=%s' % cookie['path']
        if cookie.get('domain', None):
            cookie_str += '; Domain=%s' % cookie['domain']

        return cookie_str

    def _get_request_cookies(self, jar, request):
        # 將request中cookies參數添加的cookie合並到當前的cookiejar中
        if isinstance(request.cookies, dict):
            cookie_list = [{'name': k, 'value': v} for k, v in \
                    six.iteritems(request.cookies)]
        else:
            cookie_list = request.cookies

        cookies = [self._format_cookie(x) for x in cookie_list]
        headers = {'Set-Cookie': cookies}
        # 使用剛才獲取的cookie構造一個響應對象
        response = Response(request.url, headers=headers)
        # cookiejar.make_cookies方法從response中提取cookie放入當前cookiejar中.
        return jar.make_cookies(response, request)

CookiesMiddleware默認情況下實現了cookie在請求-響應之間的流轉和填充.
又可以通過scrapy.Request(url, meta={'cookiejar': n})來實現單Spider多cookie.
通過讀源碼也解答了上一篇博文"Scrapy框架--cookie的獲取/傳遞/本地保存"中的疑惑.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM