scrapy的cookie管理
单个请求的cookie管理
1.设置headers
需要把settings.py的COOKIES_ENABLED设置为false
COOKIES_ENABLED = False
示例
def start_requests(self):
headers = {
"cookie":"填入cookie"
}
url = '请求url'
yield Request(url, callback=self.parse, headers=headers)
2.传入Request的cookies参数
需要把settings.py的COOKIES_ENABLED设置为true
示例
def start_requests(self):
url = '请求url'
# 指定你的cookies
cookies = {}
yield Request(url, callback=self.parse,cookies=cookies)
多个请求的cookie管理
上面的两个方法可适用大部分情景,但如果要管理多个cookie session,每次手动添加就显得很繁杂了。这时候就用到scrapy的cookies middleware了,其使用了cookiejar来管理多个cookie。
使用
需要把settings.py的COOKIES_ENABLED设置为true
for i, url in enumerate(urls):
yield scrapy.Request("http://www.example.com", meta={'cookiejar': i},
callback=self.parse_page)
只需这一步,scrapy就会自动帮你管理该次请求与响应的cookie了。而且这可以和headers与cookies传参的方式并存,它会自动帮你加入其管理的cookie中。
其中键必须为'cookiejar',与cookies middleware源码有关。
该代码为每一个请求的meta中的cookiejar都赋予不同的值(实际上它并不是真正的cookiejar,只是一个内部维持请求与cookiejar的对应的key),在cookies middleware中就为每一个请求都维持管理了不同的cookie。
上面这段代码初看可能会莫名其妙,但你看了源码就会一清二楚了。
需要注意的是后续的请求并不会自动维持前面的cookie。 如果后续的请求也要维持前面的cookie,需要在之后的request请求中接着传递。例如:
def parse_page(self, response):
# do some processing
return scrapy.Request("http://www.example.com/otherpage",
meta={'cookiejar': response.meta['cookiejar']},
callback=self.parse_other_page)
源码简析
本文使用源码为scrapy 2.3.0
初始化
from collections import defaultdict
from scrapy.http.cookies import CookieJar
class CookiesMiddleware:
"""This middleware enables working with sites that need cookies"""
def __init__(self, debug=False):
self.jars = defaultdict(CookieJar)
self.debug = debug
开始用defaultdict创建了self.jars,它就是实际上管理每个独立的cookiejar的字典
处理请求
def process_request(self, request, spider):
if request.meta.get('dont_merge_cookies', False):
return
cookiejarkey = request.meta.get("cookiejar")
jar = self.jars[cookiejarkey]
for cookie in self._get_request_cookies(jar, request):
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)
从cookiejarkey = request.meta.get("cookiejar")
就能看出为什么meta的key必须为'cookiejar'了。这也能看到,如果meta中有{'dont_merge_cookies': True}的键值对,就会跳过处理,当有单个请求不想合并cookie就可添加该键值对。
self._get_request_cookies
函数就是提取headers与request中的cookies的cookies并加入该cookiejar。这也解释了为什么cookiejar可与headers与cookies传参的方式并存。
最后为request加入该cookiejar管理的cookie
处理相应
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
与处理请求相似。
DEBUG
在setting.py中设置COOKIES_DEBUG = True,并且LOG_LEVEL = "DEBUG",Scrapy将记录所有在request(cookie请求头)发送的cookies及response接收到的cookies(Set-Cookie 接收头)。
下边是启用COOKIES_DEBUG 的记录的样例:
2011-04-06 14:35:10-0300 [scrapy] INFO: Spider opened
2011-04-06 14:35:10-0300 [scrapy] DEBUG: Sending cookies to: <GET http://www.diningcity.com/netherlands/index.html>
Cookie: clientlanguage_nl=en_EN
2011-04-06 14:35:14-0300 [scrapy] DEBUG: Received cookies from: <200 http://www.diningcity.com/netherlands/index.html>
Set-Cookie: JSESSIONID=B~FA4DC0C496C8762AE4F1A620EAB34F38; Path=/
Set-Cookie: ip_isocode=US
Set-Cookie: clientlanguage_nl=en_EN; Expires=Thu, 07-Apr-2011 21:21:34 GMT; Path=/
2011-04-06 14:49:50-0300 [scrapy] DEBUG: Crawled (200) <GET http://www.diningcity.com/netherlands/index.html> (referer: None)
如有纰漏,欢迎斧正