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. 通过读源码也解答了上一篇博文""中的疑惑.