zoukankan      html  css  js  c++  java
  • scrapy 基础组件专题(十四):scrapy CookiesMiddleware源码

    一 Scrapy框架--cookie的获取/传递/本地保存

    1. 完成模拟登陆
    2. 登陆成功后提取出cookie,然后保存到本地cookie.txt文件中
    3. 再次使用时从本地的cookie.txt中读取cookie,省略模拟登陆.

    Cookie的传递和提取

    from scrapy.http.cookies import CookieJar    

    # 该模块继承自内置的http.cookiejar,操作类似 # 实例化一个cookiejar对象 cookie_jar = CookieJar() # 首先是cookie的提取 class MySpider(scrapy.Spider): .... .... # 模拟登陆,之后调用一个检查是否登录成功的函数 def login(self, response): .... return [scrapy.FormRequest( url=login_url, formdata = {'username':xxx, 'password':xxx}, callback = self.check_login )] def check_login(self, response): if 登录成功: # 到这里我们的登录状态已经写入到response header中的'Set-Cookies'中了, # 使用extract_cookies方法可以提取response中的cookie cookiejar.extract_cookies(response, response.request) # cookiejar是类字典类型的,将它写入到文件中 with open('cookies.txt', 'w') as f: for cookie in cookie_jar: f.write(str(cookie) + ' ') # 有些情况可能在发起登录之前会有一些请求,会陆续的产生一些cookie,可以在第一次请求的时候将cookiejar写入到request的meta中进行传递 scrapy.Request(url, callback=self.xxx, meta={'cookiejar': cookiejar}) # 之后每次需要传递这个cookiejar对象可以从response.meta中拿到 scrapy.Request(url, callback=self.xxx, meta={'cookiejar': response.meta['cookiejar']})

    看了不少博文中只是写将cookie添加到meta中,这样就可以在请求的过程中获取到cookie.我这样尝试过,cookiejar在多个请求-响应中流转后依然是空的,所以只能在需要的时候使用cookiejar.extract_cookies方法进行手动提取.
    若哪位大神知道meta中的cookiejar自行获取cookie的方法,请评论指点,谢谢!

    从本地文件中读取Cookie

    with open('cookies.txt', 'r') as f:
             cookiejar = f.read()
             p = re.compile(r'<Cookie (.*?) for .*?>')
             cookies = re.findall(p, cookiejar)
             cookies = (cookie.split('=', 1) for cookie in cookies)
             cookies = dict(cookies)

    之后可以在第一次发起请求(start_request)时将cookie手动添加到scrapy.Requestcookies参数中,cookie在后续的请求中会自行流转.

    scrapy.Request(url, callback=self.xxx, cookies=cookies)

    二 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.

     
  • 相关阅读:
    POI导出word
    idea 右键无java class选项
    从接口输出日志中提取用例
    Java 注解
    从输出日志中提取接口的入参和返回做为用例导入到excel中
    苹果绿RGB值
    YAML详解
    Linux grep命令
    MySQL DATE_FORMAT() 函数
    sql server 备份还原
  • 原文地址:https://www.cnblogs.com/qiu-hua/p/12650067.html
Copyright © 2011-2022 走看看