一 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) + '\n') # 有些情况可能在发起登录之前会有一些请求,会陆续的产生一些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.

 

scrapy 基础组件专题(十四):scrapy CookiesMiddleware源码的更多相关文章

  1. scrapy 基础组件专题(四):信号运用

    一.scrapy信号使用的简单实例 import scrapy from scrapy import signals from ccidcom.items import CcidcomItem cla ...

  2. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  3. scrapy 基础组件专题(十二):scrapy 模拟登录

    1. scrapy有三种方法模拟登陆 1.1直接携带cookies 1.2找url地址,发送post请求存储cookie 1.3找到对应的form表单,自动解析input标签,自动解析post请求的u ...

  4. scrapy 基础组件专题(八):scrapy-redis 框架分析

    scrapy-redis简介 scrapy-redis是scrapy框架基于redis数据库的组件,用于scrapy项目的分布式开发和部署. 有如下特征:  分布式爬取 您可以启动多个spider工 ...

  5. scrapy 基础组件专题(九):scrapy-redis 源码分析

    下面我们来看看,scrapy-redis的每一个源代码文件都实现了什么功能,最后如何实现分布式的爬虫系统: connection.py 连接得配置文件 defaults.py 默认得配置文件 dupe ...

  6. scrapy 基础组件专题(七):scrapy 调度器、调度器中间件、自定义调度器

    一.调度器 配置 SCHEDULER = 'scrapy.core.scheduler.Scheduler' #表示scrapy包下core文件夹scheduler文件Scheduler类# 可以通过 ...

  7. 第十四章 Executors源码解析

    前边两章介绍了基础线程池ThreadPoolExecutor的使用方式.工作机理.参数详细介绍以及核心源码解析. 具体的介绍请参照: 第十二章 ThreadPoolExecutor使用与工作机理 第十 ...

  8. scrapy 基础组件专题(二):下载中间件

    下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个轻量.底层的系统. 1.激活Downloader Mi ...

  9. scrapy 基础组件专题(一):scrapy框架中各组件的工作流程

    Scrapy 使用了 Twisted 异步非阻塞网络库来处理网络通讯,整体架构大致如下(绿线是数据流向): Scrapy主要包括了以下组件: 引擎(Scrapy)用来处理整个系统的数据流处理, 触发事 ...

随机推荐

  1. netty实现消息中心(一)思路整理

    一.需求 需要实现直播间的以下功能: 群发消息(文本.图片.推荐商品) 点对点私发消息(文本.图片.推荐商品) 单个用户禁言 全体用户禁言 撤回消息 聊天记录持久化 二.技术实现 服务端消息中心采用n ...

  2. Excel常用公式大全

    公式是单个或多个函数的结合运用. AND “与”运算,返回逻辑值,仅当有参数的结果均为逻辑“真(TRUE)”时返回逻辑“真(TRUE)”,反之返回逻辑“假(FALSE)”. 条件判断 AVERAGE ...

  3. TensorFlow从0到1之TensorFlow逻辑回归处理MNIST数据集(17)

    本节基于回归学习对 MNIST 数据集进行处理,但将添加一些 TensorBoard 总结以便更好地理解 MNIST 数据集. MNIST由https://www.tensorflow.org/get ...

  4. 关联函数-web_reg_save_param

    int web_reg_save_param(const char *ParamName,<List of Attributes>,LAST) 返回值:成功时返回LR_PASS,失败时返回 ...

  5. JVM进阶之路(一)

    JVM是Java程序运行的基本,了解Java程序的运行原理绝对有必要了解JVM的内容,JVM的内容其实很多,而且版本不同,其中的内容也很多不同,接下来就通过几篇文章来慢慢讲述JVM的内容. 一.Jvm ...

  6. 解决错误【selenium.common.exceptions.SessionNotCreatedException】

    以前能用,突然不能用了,是浏览器版本可能升级了,与原来的weddriver驱动版本不符合 解决办法:1.更新浏览器驱动, 2.降低浏览器版本

  7. JDBC——什么是JDBC?

    JDBC:Java数据库连接(Java DataBase Connectivity),是Java语言中用来规范客户端如何程序如何来访问数据库的应用程序接口(API),提供了诸如查询和更新数据库中数据的 ...

  8. 关于自动寻路(Navigation)的初级总结

    1.使用Nav Mesh Link组件 该组件会实现寻路者从Start跳向end点 注意Player会优先选择最佳路线,且Start,End两个物体都应该在Walkable的区域上 2.使用Nav M ...

  9. 使用反应式关系数据库连接规范R2DBC操作MySQL数据库

    1. 简介 三月份已经介绍过R2DBC,它是一种异步的.非阻塞的关系式数据库连接规范.尽管一些NoSQL数据库供应商为其数据库提供了反应式数据库客户端,但对于大多数项目而言,迁移到NoSQL并不是一个 ...

  10. C#数据结构与算法系列(十九):选择排序算法(SelectSort)

    1.介绍 选择排序算法属于内部排序算法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置达到排序的目的 时间复杂度:O(n^2) 双层for 2.思想 选择排序(select sorti ...