在用浏览器进行网页访问时,会向网页所在的服务器发送http协议的GET或者POST等请求,在请求中除了指定所请求的方法以及URI以外,后面还跟随着一段Request Header。Request Header的内容主要用于描述本地信息,如所用的浏览器、所用的系统、语言、所能接受的返回数据的编码格式等,其中有一个很是重要的Header项就是Cookie,Cookie能够说是网站的自定义数据集。因为服务器端没法没法控制本地(浏览器)的内存数据,但服务器又有必要搜集与本身所提供的服务相关的本地状态信息,而Cookie就承载了这一功能,目的是记录用户在网站的状态信息。html
在用python对网页进行访问的时候,若是但愿获得与在网页端相同的结果,用该网页在浏览器中所保留的Cookie做为python的请求Cookie是一个比较值得推荐的作法。python
本文主要讨论如何提取浏览器保存在本地的Cookie,所用的浏览器为Chrome。git
Chrome用sqlite来维护Cookie,Cookie中的信息被保存在sqlite数据库当中,若是系统为Windows,那么数据库文件所在的位置为[1]:github
C:\Users\{UserName}\AppData\Local\Google\Chrome\User Data\Default\Cookies
其中该路径的{UserName}是当前系统的用户名。sql
username = os.environ.get('USERNAME') cookie_file = 'C:\Users\{UserName}\AppData\Local\Google\Chrome\User Data\Default\Cookies'.format(UserName=username)
经过Cookie文件路径,咱们能够创建数据库链接,而后提取出数据库的信息。数据库
con = sqlite3.connect(cookie_file) cursor = con.cursor()
数据库中的cookies表就是用于保存浏览器Cookie的。提取表中各列的名称windows
cursor.execute('SELECT * FROM cookies') for description in cursor.description: print(description[0])
各字段的描述以下api
上述字段中有些是只有浏览器才会用到的,这里没有必要用上,所以咱们仅须要提取一些必要字段浏览器
cursor.execute('SELECT host_key, name, value, path, expires_utc, is_secure, encrypted_value ' 'FROM cookies WHERE host_key like "%{}%";'.format(domain_name))
咱们前面说过,Chrome在对Cookie的值保存以前会进行加密处理,并保存在数据库的encrypt_value字段中。在Windows系统中,Cookie加密采用的是系统提供的函数CryptProtectData,咱们在解密的时候也须要调用系统提供的函数CryptUnprotectData[1]。解密的Windows用户必须与加密的用户一致才能成功解密。安全
不过系统提供的是C函数,python经过ctypes库来实现对C函数的调用。
CryptUnprotectData须要7个参数:
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
python并不推荐咱们去自行建立Cookie,由于做为用户一般不须要去改动,甚至没有必要知道Cookie的内容,不过此处出于特殊的需求,须要经过在Cookie数据库中获取的数据来建立Cookie。
首先咱们来简单了解一下Set-Cookie。咱们知道Cookie都是服务器为浏览器设置的,设置Cookie是经过服务器返回的Response Header,若是header中包含有Set-Cookiie相关字段,则能进行Cookie的设置。
http.cookiejar.Cookie的初始化须要提供18个参数[2]:
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: