在用浏览器进行网页访问时,会向网页所在的服务器发送http协议的GET或者POST等请求,在请求中除了指定所请求的方法以及URI之外,后面还跟随着一段Request Header。Request Header的内容主要用于描述本地信息,如所用的浏览器、所用的系统、语言、所能接受的返回数据的编码格式等,其中有一个非常重要的Header项就是Cookie,Cookie可以说是网站的自定义数据集。由于服务器端无法无法控制本地(浏览器)的内存数据,但服务器又有必要搜集与自己所提供的服务相关的本地状态信息,而Cookie就承载了这一功能,目的是记录用户在网站的状态信息。

在用python对网页进行访问的时候,如果希望得到与在网页端相同的结果,用该网页在浏览器中所保留的Cookie作为python的请求Cookie是一个比较值得推荐的做法。

本文主要讨论如何提取浏览器保存在本地的Cookie,所用的浏览器为Chrome。

Cookie文件

Chrome用sqlite来维护Cookie,Cookie中的信息被保存在sqlite数据库当中,如果系统为Windows,那么数据库文件所在的位置为:

C:\Users\{UserName}\AppData\Local\Google\Chrome\User Data\Default\Cookies

其中该路径的{UserName}是当前系统的用户名。

username = os.environ.get('USERNAME')
cookie_file = 'C:\Users\{UserName}\AppData\Local\Google\Chrome\User Data\Default\Cookies'.format(UserName=username)

Cookie表单

通过Cookie文件路径,我们可以建立数据库连接,然后提取出数据库的信息。

con = sqlite3.connect(cookie_file)
cursor = con.cursor()

数据库中的cookies表就是用于保存浏览器Cookie的。提取表中各列的名称

cursor.execute('SELECT * FROM cookies')
for description in cursor.description:
print(description[0])

各字段的描述如下:

  • creation_utc:Cookie产生的utc时间
  • host_key:Cookie所在的网页(domain)
  • name:Cookie名称
  • value:不加密的Cookie值,由于Chrome几乎都会对Cookie值加密后再存储,因此这个字段基本都是空的
  • path:如果服务器需要设置Cookies,那么服务器在响应浏览器请求的时候会返回Set-Cookie的响应,并且附带所要设置的Cookies,这里的path的默认值就是返回Set-Cookie的那个页面。path以'/'为开头。
  • expires_utc:Cookie的有效期限
  • is_secure:指示在浏览器与服务器之间传输该Cookie时需要采用加密通道,即https
  • is_httponly:当设置了该值为1时,在浏览器上运行的JS不能读取到该Cookie,该Cookie只能由http请求读取。这个标记主要目的是提高Cookie的安全性,防止无关的JS脚本窃取Cookie中的重要信息
  • last_access_utc:上一次访问到该Cookie的时间
  • has_expires:Cookie的期限是否有效
  • is_persistent:如果expires_utc不为0,那么这个值为1
  • priority:Cookie的删除优先级,Cookie也有存储上限的,当超出上限则需要删除,此时会有特定的删除策略来删除不同priority的Cookie
  • encrypted_value:加密后的Cookie值
  • firstpartyonly:first-party以及third-party是HTTP Request的一种分类,first-party指的是当前所发送的HTTP请求的URL跟浏览器地址栏上的URL一致;否则就是third-party。如我们平常看到的很多网页上的图片或者广告,其实都是third-party request。无论first-party或者third-party,都是HTTP请求,在往服务器发送请求的时候会带上host为该URL的Cookies,不过如果一个Cookie指定了firstpartyonly,那么如果请求为thrid-party,在发送请求的时候不会附带该Cookie。以上面所说的网页中的图片为例子,如果该图片URL的Cookie设定为firstpartyonly,在浏览网站时,通过third-party访问了该图片所在的URL,就不会发送该Cookie。

上述字段中有些是只有浏览器才会用到的,这里没有必要用上,因此我们仅需要提取一些必要字段。

domain_name = 'blog.csdn.net'
cursor.execute('SELECT host_key, name, value, path, expires_utc, is_secure, encrypted_value '
'FROM cookies WHERE host_key like "%{}%";'.format(domain_name))

解密Cookie

我们前面说过,Chrome在对Cookie的值保存之前会进行加密处理,并保存在数据库的encrypt_value字段中。在Windows系统中,Cookie加密采用的是系统提供的函数CryptProtectData,我们在解密的时候也需要调用系统提供的函数CryptUnprotectData[1]。解密的Windows用户必须与加密的用户一致才能成功解密。

不过系统提供的是C函数,python通过ctypes库来实现对C函数的调用。

CryptUnprotectData需要7个参数:

  • pDataIn:一个指向DATA_BLOB结构体的指针,该DATA_BLOB内需存放被解密的数据。DATA_BLOB结构体内含两个成员:cbData,数据的所占用的字节数;pbData,指向数据所在内存的指针。
  • ppszDataDescr:描述该加密数据的信息,如果在进行加密操作的时候添加了描述,那么在解密的时候也能得到该描述信息。获得该描述后需要调用系统提供的LocalFree释放ppszDataDescr指向的内存。如果不需要,设为NULL即可。
  • pOptionalEntropy:一个指向含有密钥DATA_BLOB的指针,不过在进行Cookie加密时通常不会用到。
  • pvReserved:保留参数,设为NULL即可。
  • pPromptStruct:解密是一个有安全风险的操作,可能需要弹出风险提升,如果不需要弹出提示设置为NULL即可。
  • dwFlags:安全相关的标志,设置为0即可。
  • pDataOut:一个指向解密后的数据的DATA_BLOB,获得解密数据后需要调用系统提供的LocalFree函数释放pbData指向的内存。
class DATA_BLOB(ctypes.Structure):
_fields_ = [("cbData", ctypes.wintypes.DWORD),
("pbData", ctypes.POINTER(ctypes.c_char))]
def __init__(self, data):
string = str(data)
self.cbData = len(string)
self.pbData = ctypes.create_string_buffer(string) def descrypt(cipher):
#parameters
DataIn = DATA_BLOB(cipher)
Descr = ctypes.c_wchar_p()
DataEntropy = DATA_BLOB('')
Reserved = None
PromptStruct = None
CRYPTPROTECT_UI_FORBIDDEN = 0x00
DataOut = DATA_BLOB('')
#win call
ret = ctypes.windll.crypt32.CryptUnprotectData(ctypes.byref(DataIn),
Descr,
ctypes.byref(DataEntropy),
Reserved,
PromptStruct,
CRYPTPROTECT_UI_FORBIDDEN,
ctypes.byref(DataOut)
)
if not ret:
raise RuntimeError("failed to descrypt") buf = ctypes.create_string_buffer(int(DataOut.cbData))
ctypes.memmove(buf, DataOut.pbData, DataOut.cbData)
ctypes.windll.kernel32.LocalFree(Descr)
ctypes.windll.kernel32.LocalFree(DataOut.pbData)
return buf.value

创建Cookie并填充CookieJar

python并不推荐我们去自行创建Cookie,因为作为用户通常不需要去改动,甚至没有必要知道Cookie的内容,不过此处出于特殊的需求,需要通过在Cookie数据库中获取的数据来创建Cookie。

首先我们来简单了解一下Set-Cookie。我们知道Cookie都是服务器为浏览器设置的,设置Cookie是通过服务器返回的Response Header,如果header中包含有Set-Cookiie相关字段,则能进行Cookie的设置。

http.cookiejar.Cookie的初始化需要提供18个参数:

  • version:比较老版本的Cookie(如rfc2109,已淘汰)要求Cookie必须有Version字段,不过较新的版本(如rfc6265)的Cookie去掉了这一字段,因此这里填0就行。
  • name:Cookie名称
  • value:Cookie值
  • port:http端口,指定了该字段的Cookie只能发送到服务器的指定端口,只有rfc2965中的Set-Cookie2才用到该字段,rfc2695是一个已淘汰的版本,这里填None就行。
  • port_specified:是否有指定端口,同样是已淘汰的参数,填False。
  • domain:服务器域名
  • domain_specified:是否指定了服务器域名
  • domain_initial_dot:服务器域名是否以"."作为开头
  • path:服务器路径
  • path_specified:是否指定了服务器路径
  • secure:是否采用安全通道
  • expires:Cookie期限
  • discard:是否为一次性Cookie,同上方的is_persistent,填False
  • comment:Cookie注释,填None
  • comment_url:Cookie注释所在的URL,填None
  • rest:存储该Cookie的一些非标准的属性,填{}
  • rfc2109:是否为rfc2109标准,默认值为False
cj = http.cookiejar.CookieJar()
for row in cursor.fetchall():
host, name, value, path, expires, secure, encrypted_value = row[:]
data = descrypt(encrypted_value)
c = http.cookiejar.Cookie(0, name, data, None, False, host, host.startswith('.'), host.startswith('.'),
path, True, secure, expires, False, None, None, {})
cj.set_cookie(c)

其中比较重要的domain相关参数请查看:rfc2109的Interpreting Set-Cookie、Rejecting Cookies以及rfc6265的The Domain Attribute、Storage Model。

Reference

  1. Client Side HTTP Cookie Security
  2. cookiejar.Cookie

注:
本文转自[《python提取浏览器Cookie》](https://www.cnblogs.com/TaigaCon/p/9721697.html)

作者:博客园 TaigaComplex求职中

转:python提取浏览器Cookie的更多相关文章

  1. python提取浏览器Cookie

    在用浏览器进行网页访问时,会向网页所在的服务器发送http协议的GET或者POST等请求,在请求中除了指定所请求的方法以及URI之外,后面还跟随着一段Request Header.Request He ...

  2. Chrome浏览器Cookie解密

    做过 web 开发的都知道:浏览器会把重要的认证登录认证信息存放到 cookie 中,在 cookie 有效期内,再次访问这个网站的时候就可以直接从 cookie 中获取到登录信息,这样就可以实现自动 ...

  3. python 模拟浏览器

    想用python模拟浏览器访问web的方法测试些东西,有哪几种方法呢? 一类:单纯的访问web,不解析其js,css等. 1. urllib2 #-*- coding:utf-8 -* import ...

  4. IE浏览器Cookie信息提取工具Galleta

    IE浏览器Cookie信息提取工具Galleta   浏览器Cookie中保存着用户访问网站的各项敏感信息,如用户登录凭证.提取这些信息后,就可以以该用户的身份访问对应的网站.为了方便信息获取,Kal ...

  5. 第14.7节 Python模拟浏览器访问实现http报文体压缩传输

    一. 引言 在<第14.6节 Python模拟浏览器访问网页的实现代码>介绍了使用urllib包的request模块访问网页的方法.但上节特别说明http报文头Accept-Encodin ...

  6. 关于浏览器cookie的那些事儿

    昨天接到一个小需求,就是在ipad上访问某页面,页面顶部出现一个下载客户端的提示,点击关闭按钮后,提示信息消失,信息存入cookie,在cookie未过期之前,除非用户自己清除浏览器的cookie,否 ...

  7. 浏览器cookie数

    <?php for ($w=0; $w < 200 ; $w++) { setcookie('name'.$w,'value'.$w, time()+3600*10 ); } var_du ...

  8. selenium + python 多浏览器测试

    selenium + python 多浏览器测试 支持库包 在学习 Python + Selenium 正篇之前,先来看下对多浏览器模拟的支持.目前selenium包中已包含webdriver,hel ...

  9. Python提取图片的ROI

    图像处理经常需要提取图片的ROI,本文使用Python提取图片的ROI. 使用的Module是PIL (Pillow),一个图像处理库,用到的函数为类 Image 中的 crop 方法. 函数原型为: ...

随机推荐

  1. C++ stringstream 实现字符与数字之间的转换

    c++中利用srtingstream可以将数字转为字符串,或者将字符串转为数字: 首先将double型数字串转成了string: stringnum2string(double *a,int n) { ...

  2. CC模型加载太慢?一招破解!

    伴随无人机性能的提升,单个项目涉及到的倾斜摄影数据范围不断扩大,模型的数据量越来越大,在同配置机器上的显示速度也相应的越来越慢,那么如何在不升级配置的情况下提升模型的加载速度呢? 01 百GB倾斜摄影 ...

  3. GMP-C/C++(大数库)使用方法

    The GNU Multiple Precision Arithmetic Library(GNU 高精度算数库)是一个用于任意精度算术的免费库,可处理带符号整数,有理数和浮点数.除了运行GMP机器中 ...

  4. Git仓库的提交记录乱成一团,怎么办?

    大家好,今天和大家聊聊git当中一个非常好用的功能--区间选择,它可以帮我们处理看起来非常复杂的提交记录.从而帮助我们很快找到我们需要的内容. 如果大家有参与过多人协同的项目开发,比如十几个人甚至更多 ...

  5. 【JVM第五篇--运行时数据区】方法区

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.栈.堆.方法区的关系 虚拟机运行时的数据区如下所示: 即方法区是属于线程共享的内 ...

  6. ceph luminous版本限制osd的内存使用

    引言 ceph自从到了L版本以后,L版本的启用,对性能本身有了极大的提高,一直对这个比较不放心的就是内存的占用,刚开始的时候记得大量dd就可以把内存搞崩掉,这个应该是内部的设计逻辑需要更多的内存的占用 ...

  7. redhat-NFS服务的配置与应用

    ---恢复内容开始--- 1.NFS服务简述 NFS实现Windows系统中资源共享的功能.NFS采用客户/服务器工作模式,客户端将服务器中的共享目录挂载到自己的某个目录下,这个目录可以与其他客户机的 ...

  8. 应聘阿里,字节跳动,美团必须掌握的Spring IOC与工厂模式

    Spring IOC与工厂模式 PS:本文内容较为硬核,需要对java的面向对象.反射.类加载器.泛型.properties.XML等基础知识有较深理解. (一)简单介绍 在讲Spring IOC之前 ...

  9. 新鲜出炉!凭借着这份面试宝典,我终于拿下了字节跳动的offer!

    前言 我做Java也十来年了,现在也算是中层管理,每次招聘都需要找一些面试题,干脆自己整理了一份,这份面试宝典是从我 去年开始收集的,一方面是给公司招聘用,另一方面也是想用它,来挖掘自己在 Java ...

  10. 左右声道音频怎么制作,用Vegas就对啦

    一款优秀的视频剪辑软件,不仅有高水平的视频制作功能,它的音频编辑功能也是必不可少的.Vegas就是这么一款软件,同时具备视频制作特效制作的同时,还能帮助制作轨道音频效果. 下面,就让小编带大家去学习, ...