CookiesMiddleware源码分析

import os
import six
import logging
from collections import defaultdict

from scrapy.exceptions import NotConfigured
from scrapy.http import Response
from scrapy.http.cookies import CookieJar
from scrapy.utils.python import to_native_str

logger = logging.getLogger(__name__)


class CookiesMiddleware(object):
    """This middleware enables working with sites that need cookies"""

    def __init__(self, debug=False):
        self.jars = defaultdict(CookieJar)
        self.debug = debug

    @classmethod
    def from_crawler(cls, crawler):
        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

        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
        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)
        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]
        jar.extract_cookies(response, request)
        self._debug_set_cookie(response, spider)

        return response

    def _debug_cookie(self, request, spider):
        if self.debug:
            cl = [to_native_str(c, errors='replace')
                  for c in request.headers.getlist('Cookie')]
            if cl:
                cookies = "\n".join("Cookie: {}\n".format(c) for c in cl)
                msg = "Sending cookies to: {}\n{}".format(request, cookies)
                logger.debug(msg, extra={'spider': spider})

    def _debug_set_cookie(self, response, spider):
        if self.debug:
            cl = [to_native_str(c, errors='replace')
                  for c in response.headers.getlist('Set-Cookie')]
            if cl:
                cookies = "\n".join("Set-Cookie: {}\n".format(c) for c in cl)
                msg = "Received cookies from: {}\n{}".format(response, cookies)
                logger.debug(msg, extra={'spider': spider})

    def _format_cookie(self, cookie):
        # build cookie string
        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):
        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}
        response = Response(request.url, headers=headers)

        return jar.make_cookies(response, request)

 

 

 

  • from_crawler方法                                                                                                                                                                       从配置文件中读取COOKIE_ENABLEED,决定是否启用该中间件。如果启用,调用构造器创建对象,否则抛出NotConfigured异常,Scrapy将忽略该中间件。
  • __init__                                                                                                                                                                                       使用标准库中的collections.defaultdict创建一个默认字典self.jars,该字典中每一项的值都是一个scrappy.http.cookies.CookieJar对象,CookiesMiddleware可以让爬虫同时使用多个不同的CookieJar。例如,在某网站有两个账号,如果想让爬虫同时登陆两个账号进行爬取,为了避免Cookie冲突,可以让两个账号发送的HTTP请求使用不同的CookieJar,在构造Request对象时,可以 通过meta参数的cookiejar字段指定所要使用的CookieJar
  • #账号account1发送的请求
    Request(url1,meta={'cookiejar' : 'account1'})
    Request(url2,meta={'cookiejar' : 'account1'})
    Request(url3,meta={'cookiejar' : 'account1'})
    
    #账号account2发送的请求
    Request(url1,meta={'cookiejar' : 'account2'})
    Request(url2,meta={'cookiejar' : 'account2'})
    Request(url3,meta={'cookiejar' : 'account2'})

    process_request方法                                                                                                                                                                  处理每一个待发送的Request对象,尝试从request.meta.get("cookiejar")获取用户指定使用的CookieJar,如果用户未指定,就使用默认的CookieJar(self.jars[None])。调用的self._get_request_cookies方法获取发送请求request应携带的Cookie信息,填写到HTTP请求头部。

  •  process_response方法                                                                                                                                                             处理每一个Response对象,依然通过request.meta.get("cookiejar")获取CookieJar对象,调用extract_cookies方法将HTTP响应头部中的Cookie信息保存到CookieJar对象中。

这里的CookieJar是 

scrapy.http.cookies.CookieJar

非http.cookies.CookieJar,它们是不同的类Scrappy对http.cookies.CookieJar进行了包装,它们可以互相转化。

 

 

 CookiesMiddleware自动处理Cookie的特性给用户提供了便利,但是它不能使用浏览器的Cookie,我们可以利用browsercookie对CookiesMiddleware,进行改良,实现一个能使用浏览器的Cookie的中间件。

 

import browsercookie
from scrapy.downloadermiddlewares.cookies import CookiesMiddleware

class BrowserCookiesMiddleware(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)
            
         #加载Firefox浏览器中的Cookie   
        jar = self.jars['firefox']
        firefox_cookiejar = browsercookie.firefox()
        for cookie in firefox_cookiejar:
            jar.set_cookie(cookie)

 

在构造 BrowserCookiesMiddleware 对象时,使用browsercookie将浏览器中的 Cookie 提取,存储到CookieJar字典self.jars中

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

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值