- 操作系统:windows 10 x64
- 集成环境:Visual Studio Code
- Python版本:v3.10.5 64位
– 解码需要os、sqlite3、win32crypt、base64、cryptography、json库
– 访问网页需要urllib、http库
本文是承接另一篇博文基于Python通过Chrome的Cookie登录百度账户的姊妹篇。在对代码进行封装后,尝试对CSDN进行访问。对于一些思路的说明,可以参考上文。
二、工程文件结构三、资源构建 1、在resource文件夹内创建配置文件config工程目录
- [dir] log
- [dir] modules
- [dir] resource
- [file] main.py
- [file] app.py
resource
- [file] config
内容如下:
{
".csdn.net": ["TRUE","FALSE"],
".www.csdn.net": ["TRUE","FALSE"]
}
2、在modules文件夹内创建支持模块conn.py、cookie.py、decode.py,_init_.py:
modules
- [file] conn.py
- [file] cookie.py
- [file] decode.py
- [file] _init_.py.py
内容如下:
2.1 conn.py,继承于Connection类,加了上下文管理方便使用with调用
import sqlite3
from typing import *
class Conn(sqlite3.Connection):
def __init__(self, path) -> None:
super().__init__(path)
self._path = path
def __enter__(self) -> sqlite3.Connection.cursor:
return self.cursor()
def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
self.cursor().close()
self.close()
if exc_traceback is None:
...
else:
...
def __repr__(self) -> str:
return '_conn(path = %s)' % self._path
2.2 cookie.py,用于将给的原材料加工成可以使用的cookie文件
import json
import time
from typing import *
with open('./resource/config', 'r') as f:
BAIDU_BOOL = json.load(f)
# cookie文件头,最后一步手工生成cookie会用得到
COOKIE_HEADER = """# Netscape HTTP Cookie Filen# http://curl.haxx.se/rfc/cookie_spec.htmln# This is a generated file! Do not edit.nn"""
class Cookie:
'''这个类可以用来生成cookie文件'''
def __init__(self, cookieList: List[Tuple[str, str, str, str, str]]) -> None:
self.cookieList = cookieList
def __repr__(self) -> str:
return 'Cookie(count=%d)' % len(self.cookieList)
def getOne(self):
'''此方法可以将cookie封装成生成器对象,通过next()函数调用'''
for i in self.cookieList:
creation_utc, host_key, name, value, path = i
cookieContent = str(host_key) + 't' + str(BAIDU_BOOL[host_key][0] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(path) + 't' + str(
BAIDU_BOOL[host_key][1] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(creation_utc) + 't' + str(name) + 't' + str(value)
yield cookieContent
def getAll(self):
'''此方法可以将cookie的所有内容输出到控制台'''
for i in self.cookieList:
creation_utc, host_key, name, value, path = i
cookieContent = str(host_key) + 't' + str(BAIDU_BOOL[host_key][0] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(path) + 't' + str(
BAIDU_BOOL[host_key][1] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(creation_utc) + 't' + str(name) + 't' + str(value)
print(cookieContent)
def getOutFile(self, path: str = './log/'):
'''此方法可以将cookie封装进文件'''
with open(path + 'Cookie'+str(int(time.time())) + '.log', 'w') as f:
# 写入头
f.write(COOKIE_HEADER)
# 写入体
for i in self.cookieList:
creation_utc, host_key, name, value, path = i
cookieContent = str(host_key) + 't' + str(BAIDU_BOOL[host_key][0] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(path) + 't' + str(
BAIDU_BOOL[host_key][1] if host_key in BAIDU_BOOL.keys() else 'FALSE') + 't' + str(creation_utc) + 't' + str(name) + 't' + str(value) + 'n'
f.write(cookieContent)
2.3 decode.py,用于解密chrome浏览器的cookie
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import json
import base64
import win32crypt
def DecodeKey(path: str) -> str:
'''本函数用于将local state中封装的密钥解密出来'''
with open(path, 'r', encoding='utf-8') as f:
jsonStr = json.load(f)
encryptedKey = jsonStr['os_crypt']['encrypted_key']
encrypted_key_with_header = base64.b64decode(encryptedKey)
encrypted_key = encrypted_key_with_header[5:]
return win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]
def DecodeValue(bytes: bytes, key: str) -> str:
'''本函数用于将cookie中加密的value解密出来'''
# 根据百度的结果,valEncrypted的构成分为三部分,都是固定长度
nonce = bytes[3:15]
cipherbytes = bytes[15:]
aesgcm = AESGCM(key)
plainbytes = aesgcm.decrypt(nonce, cipherbytes, None)
return plainbytes.decode('utf-8')
2.4 _init_.py,头文件
from . conn import * from . cookie import * from . decode import *四、主程序构建 1、构建main.py,用于获取csdn的cookie
from modules import *
import os
# 存储cookie、密钥的文件路径
CHROME_COOKIE_PATH = r'GoogleChromeUser DataDefaultnetworkCookies'
CHROME_LOCALSTATE_PATH = r'GoogleChromeUser DataLocal State'
path = os.environ['LOCALAPPDATA']
dbCookies = path + CHROME_COOKIE_PATH # cookie文件,本质是一个sqlite数据库
fileLocalState = path + CHROME_LOCALSTATE_PATH # 存储密钥的文件,本质是一个Json文件
# 通过模糊搜索csdn寻找cookie
KEY_WORD = r'%csdn%'
with Conn(dbCookies) as cur:
sql = """select creation_utc,host_key,name,encrypted_value,path from cookies where host_key like '%s'""" % KEY_WORD
cur.execute(sql)
valCookiesWithEncode = cur.fetchall()
valCookiesWithDecode = []
# 从Local State文件里获取key
key = DecodeKey(fileLocalState)
for i in valCookiesWithEncode:
creation_utc, host_key, name, valEncrypted, path = i
value = DecodeValue(valEncrypted, key)
valCookiesWithDecode.append(
tuple((creation_utc, host_key, name, value, path)))
cookies = Cookie(valCookiesWithDecode)
cookies.getOutFile()
2、构建app.py,用于访问CSDN
这一步相对灵活,根据实际情况更新header。在浏览器上多用F12,如果爬取失败,检查一下爬取的内容是否藏在了XHR里面了。
from urllib.parse import *
from urllib.request import *
from http.cookiejar import *
import time
import ssl
import gzip
import re
ssl._create_default_https_context = ssl._create_unverified_context
# 要爬取的网页,注意csnd的网页内容不一定就在地址栏上,可能存放于xhr里面
url = 'https://bizapi.csdn.net/community-personal/v1/get-work?username=weixin_41936572'
# 建议将要爬取的网页里所有的header属性全部带进来(遇到:开头的可以删掉:)
# 这个headers不能直接用,我删了一些东西,请自己制作headers
headers = {
'authority': 'bizapi.csdn.net',
'method': 'GET',
'path': '/community-personal/v1/get-work?username=weixin_41936572',
'scheme': 'https',
'accept': 'application/json, text/plain, */*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'no-cache',
'cookie': '',
'origin': 'https://i.csdn.net',
'pragma': 'no-cache',
'referer': 'https://i.csdn.net/',
'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': 1,
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
'x-ca-key': 203796071,
'x-ca-nonce': '',
'x-ca-signature': '',
'x-ca-signature-headers': 'x-ca-key,x-ca-nonce'
}
# 这一步的文件改成自己通过main.py抓到的版本
cookie_jar = MozillaCookieJar('./log/Cookie1658368460.log')
cookie_jar.load(ignore_discard=True, ignore_expires=True)
cookie_processor = HTTPCookieProcessor(cookie_jar)
opener = build_opener(cookie_processor)
request = Request(url, headers=headers, method='GET')
response = opener.open(request)
data = response.read()
print(gzip.decompress(data))
cookie_jar.save('./log/Cookie'+str(int(time.time())) + '.log',
ignore_discard=True, ignore_expires=True)



