style: 统一 Ruff 代码格式
This commit is contained in:
+193
-52
@@ -4,46 +4,78 @@ from typing import Any
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Cipher import PKCS1_v1_5, AES
|
||||
|
||||
|
||||
# 随机产生4个字符组成的字符串
|
||||
def four_random_chart() -> str:
|
||||
return hex(int(65536 * (1 + random.random())))[2:][1:]
|
||||
|
||||
|
||||
# PKCS#1 v1.5 填充 + RSA 加密
|
||||
def parse_jsbn_bigint(n_obj:dict[Any, int]) -> int:
|
||||
def parse_jsbn_bigint(n_obj: dict[Any, int]) -> int:
|
||||
DB = 28
|
||||
DV = 1 << DB
|
||||
t = n_obj['t']
|
||||
t = n_obj["t"]
|
||||
|
||||
result = 0
|
||||
for i in range(t):
|
||||
result += n_obj[i] * (DV ** i)
|
||||
result += n_obj[i] * (DV**i)
|
||||
|
||||
return result
|
||||
|
||||
def encrypt_data(plaintext:str) -> str:
|
||||
|
||||
def encrypt_data(plaintext: str) -> str:
|
||||
cipher = PKCS1_v1_5.new(public_key)
|
||||
encrypted = cipher.encrypt(plaintext.encode('utf-8'))
|
||||
encrypted = cipher.encrypt(plaintext.encode("utf-8"))
|
||||
# 转换为十六进制,确保偶数长度
|
||||
hex_result = encrypted.hex()
|
||||
if len(hex_result) % 2 == 1:
|
||||
hex_result = '0' + hex_result
|
||||
hex_result = "0" + hex_result
|
||||
return hex_result
|
||||
|
||||
def RSA_jiami_r(str_16:str) -> str:
|
||||
|
||||
def RSA_jiami_r(str_16: str) -> str:
|
||||
global public_key
|
||||
# 你的数据
|
||||
n_data = {
|
||||
0: 134982529, 1: 254232810, 2: 164556709, 3: 234907349,
|
||||
4: 134685994, 5: 35463984, 6: 258277946, 7: 12518857,
|
||||
8: 44638621, 9: 93783641, 10: 212253739, 11: 62792472,
|
||||
12: 186688352, 13: 109500232, 14: 182488077, 15: 261196188,
|
||||
16: 26354094, 17: 103248217, 18: 106891695, 19: 165771045,
|
||||
20: 41530993, 21: 263704736, 22: 111785174, 23: 12753611,
|
||||
24: 232116673, 25: 155524985, 26: 218291229, 27: 122452343,
|
||||
28: 248250238, 29: 118739550, 30: 251169095, 31: 129059733,
|
||||
32: 149835464, 33: 5498868, 34: 71719731, 35: 154456417,
|
||||
0: 134982529,
|
||||
1: 254232810,
|
||||
2: 164556709,
|
||||
3: 234907349,
|
||||
4: 134685994,
|
||||
5: 35463984,
|
||||
6: 258277946,
|
||||
7: 12518857,
|
||||
8: 44638621,
|
||||
9: 93783641,
|
||||
10: 212253739,
|
||||
11: 62792472,
|
||||
12: 186688352,
|
||||
13: 109500232,
|
||||
14: 182488077,
|
||||
15: 261196188,
|
||||
16: 26354094,
|
||||
17: 103248217,
|
||||
18: 106891695,
|
||||
19: 165771045,
|
||||
20: 41530993,
|
||||
21: 263704736,
|
||||
22: 111785174,
|
||||
23: 12753611,
|
||||
24: 232116673,
|
||||
25: 155524985,
|
||||
26: 218291229,
|
||||
27: 122452343,
|
||||
28: 248250238,
|
||||
29: 118739550,
|
||||
30: 251169095,
|
||||
31: 129059733,
|
||||
32: 149835464,
|
||||
33: 5498868,
|
||||
34: 71719731,
|
||||
35: 154456417,
|
||||
36: 49635,
|
||||
't': 37, 's': 0
|
||||
"t": 37,
|
||||
"s": 0,
|
||||
}
|
||||
|
||||
e = 65537
|
||||
@@ -54,11 +86,12 @@ def RSA_jiami_r(str_16:str) -> str:
|
||||
encrypted = encrypt_data(str_16)
|
||||
return encrypted
|
||||
|
||||
|
||||
# AES加密
|
||||
# 加密模式: AES-CBC
|
||||
# 密钥长度: 128位
|
||||
# IV: 固定为 "0000000000000000"
|
||||
def parse_string_to_wordarray(text:str) -> list[int]:
|
||||
def parse_string_to_wordarray(text: str) -> list[int]:
|
||||
"""将字符串转换为 WordArray 格式"""
|
||||
length = len(text)
|
||||
words = []
|
||||
@@ -81,13 +114,15 @@ def parse_string_to_wordarray(text:str) -> list[int]:
|
||||
words[word_index] |= char_code << shift
|
||||
|
||||
return words
|
||||
def AES_O(plaintext:str, str_16:str) -> list[int]:
|
||||
|
||||
|
||||
def AES_O(plaintext: str, str_16: str) -> list[int]:
|
||||
# 密钥
|
||||
key_words = parse_string_to_wordarray(str_16)
|
||||
key = b''.join(w.to_bytes(4, 'big') for w in key_words)
|
||||
key = b"".join(w.to_bytes(4, "big") for w in key_words)
|
||||
|
||||
# IV
|
||||
iv = b'0000' * 4 # "0000000000000000"
|
||||
iv = b"0000" * 4 # "0000000000000000"
|
||||
|
||||
# 填充(PKCS7)
|
||||
pad_len = 16 - len(plaintext) % 16
|
||||
@@ -100,13 +135,14 @@ def AES_O(plaintext:str, str_16:str) -> list[int]:
|
||||
# 结果是字节数组
|
||||
return list(ciphertext)
|
||||
|
||||
|
||||
# 自定义base64编码
|
||||
def geetest_base64_encode(data:list[int]) -> dict[str, Any]:
|
||||
def geetest_base64_encode(data: list[int]) -> dict[str, Any]:
|
||||
"""极验自定义Base64编码"""
|
||||
|
||||
# 配置
|
||||
charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()'
|
||||
pad_char = '.'
|
||||
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()"
|
||||
pad_char = "."
|
||||
|
||||
# 位掩码 (这些是打乱的)
|
||||
masks = [7274496, 9483264, 19220, 235]
|
||||
@@ -159,13 +195,10 @@ def geetest_base64_encode(data:list[int]) -> dict[str, Any]:
|
||||
|
||||
break
|
||||
|
||||
return {
|
||||
"res": encoded,
|
||||
"end": padding
|
||||
}
|
||||
return {"res": encoded, "end": padding}
|
||||
|
||||
|
||||
def encrypt_string(e:str, t:list[int], n:str) -> str:
|
||||
def encrypt_string(e: str, t: list[int], n: str) -> str:
|
||||
"""
|
||||
JS加密函数的Python实现
|
||||
|
||||
@@ -185,7 +218,7 @@ def encrypt_string(e:str, t:list[int], n:str) -> str:
|
||||
|
||||
# 每次读取2个字符(十六进制)
|
||||
while o < len(n):
|
||||
r = n[o:o + 2] # 取2个字符
|
||||
r = n[o : o + 2] # 取2个字符
|
||||
if len(r) < 2:
|
||||
break
|
||||
o += 2
|
||||
@@ -205,7 +238,7 @@ def encrypt_string(e:str, t:list[int], n:str) -> str:
|
||||
return i
|
||||
|
||||
|
||||
def simple_md5(message:str) -> str:
|
||||
def simple_md5(message: str) -> str:
|
||||
"""
|
||||
简化版MD5实现,结构更清晰
|
||||
"""
|
||||
@@ -216,31 +249,139 @@ def simple_md5(message:str) -> str:
|
||||
|
||||
# 轮移位常量
|
||||
shifts = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
|
||||
7,
|
||||
12,
|
||||
17,
|
||||
22,
|
||||
7,
|
||||
12,
|
||||
17,
|
||||
22,
|
||||
7,
|
||||
12,
|
||||
17,
|
||||
22,
|
||||
7,
|
||||
12,
|
||||
17,
|
||||
22,
|
||||
5,
|
||||
9,
|
||||
14,
|
||||
20,
|
||||
5,
|
||||
9,
|
||||
14,
|
||||
20,
|
||||
5,
|
||||
9,
|
||||
14,
|
||||
20,
|
||||
5,
|
||||
9,
|
||||
14,
|
||||
20,
|
||||
4,
|
||||
11,
|
||||
16,
|
||||
23,
|
||||
4,
|
||||
11,
|
||||
16,
|
||||
23,
|
||||
4,
|
||||
11,
|
||||
16,
|
||||
23,
|
||||
4,
|
||||
11,
|
||||
16,
|
||||
23,
|
||||
6,
|
||||
10,
|
||||
15,
|
||||
21,
|
||||
6,
|
||||
10,
|
||||
15,
|
||||
21,
|
||||
6,
|
||||
10,
|
||||
15,
|
||||
21,
|
||||
6,
|
||||
10,
|
||||
15,
|
||||
21,
|
||||
]
|
||||
|
||||
# K常数(与JavaScript版本中的常数对应)
|
||||
K = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
0xD76AA478,
|
||||
0xE8C7B756,
|
||||
0x242070DB,
|
||||
0xC1BDCEEE,
|
||||
0xF57C0FAF,
|
||||
0x4787C62A,
|
||||
0xA8304613,
|
||||
0xFD469501,
|
||||
0x698098D8,
|
||||
0x8B44F7AF,
|
||||
0xFFFF5BB1,
|
||||
0x895CD7BE,
|
||||
0x6B901122,
|
||||
0xFD987193,
|
||||
0xA679438E,
|
||||
0x49B40821,
|
||||
0xF61E2562,
|
||||
0xC040B340,
|
||||
0x265E5A51,
|
||||
0xE9B6C7AA,
|
||||
0xD62F105D,
|
||||
0x02441453,
|
||||
0xD8A1E681,
|
||||
0xE7D3FBC8,
|
||||
0x21E1CDE6,
|
||||
0xC33707D6,
|
||||
0xF4D50D87,
|
||||
0x455A14ED,
|
||||
0xA9E3E905,
|
||||
0xFCEFA3F8,
|
||||
0x676F02D9,
|
||||
0x8D2A4C8A,
|
||||
0xFFFA3942,
|
||||
0x8771F681,
|
||||
0x6D9D6122,
|
||||
0xFDE5380C,
|
||||
0xA4BEEA44,
|
||||
0x4BDECFA9,
|
||||
0xF6BB4B60,
|
||||
0xBEBFBC70,
|
||||
0x289B7EC6,
|
||||
0xEAA127FA,
|
||||
0xD4EF3085,
|
||||
0x04881D05,
|
||||
0xD9D4D039,
|
||||
0xE6DB99E5,
|
||||
0x1FA27CF8,
|
||||
0xC4AC5665,
|
||||
0xF4292244,
|
||||
0x432AFF97,
|
||||
0xAB9423A7,
|
||||
0xFC93A039,
|
||||
0x655B59C3,
|
||||
0x8F0CCC92,
|
||||
0xFFEFF47D,
|
||||
0x85845DD1,
|
||||
0x6FA87E4F,
|
||||
0xFE2CE6E0,
|
||||
0xA3014314,
|
||||
0x4E0811A1,
|
||||
0xF7537E82,
|
||||
0xBD3AF235,
|
||||
0x2AD7D2BB,
|
||||
0xEB86D391,
|
||||
]
|
||||
|
||||
# 实际实现...
|
||||
return verify_result(message)
|
||||
return verify_result(message)
|
||||
|
||||
@@ -11,6 +11,7 @@ REQUEST_TIMEOUT = (3.05, 12)
|
||||
def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
|
||||
return cv2.cvtColor(np.asarray(img), flag)
|
||||
|
||||
|
||||
# 识别图片缺口返回滑块距离
|
||||
def shibie(img: Image.Image, slice: Image.Image):
|
||||
# 通过 pilImgToCv2 将图片置灰
|
||||
@@ -38,20 +39,70 @@ def shibie(img: Image.Image, slice: Image.Image):
|
||||
# showImg(resultBg) # 可以通过它来看处理后的图片效果
|
||||
return distance
|
||||
|
||||
|
||||
# 还原图片
|
||||
def restore_geetest_image(input_path:str, output_path:str) -> None:
|
||||
def restore_geetest_image(input_path: str, output_path: str) -> None:
|
||||
"""
|
||||
还原极验打乱的验证码图像
|
||||
"""
|
||||
Ut = [
|
||||
39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29,
|
||||
27, 26, 36, 37, 31, 30, 44, 45, 43, 42, 12, 13, 23, 22, 14, 15,
|
||||
21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17
|
||||
39,
|
||||
38,
|
||||
48,
|
||||
49,
|
||||
41,
|
||||
40,
|
||||
46,
|
||||
47,
|
||||
35,
|
||||
34,
|
||||
50,
|
||||
51,
|
||||
33,
|
||||
32,
|
||||
28,
|
||||
29,
|
||||
27,
|
||||
26,
|
||||
36,
|
||||
37,
|
||||
31,
|
||||
30,
|
||||
44,
|
||||
45,
|
||||
43,
|
||||
42,
|
||||
12,
|
||||
13,
|
||||
23,
|
||||
22,
|
||||
14,
|
||||
15,
|
||||
21,
|
||||
20,
|
||||
8,
|
||||
9,
|
||||
25,
|
||||
24,
|
||||
6,
|
||||
7,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
11,
|
||||
10,
|
||||
4,
|
||||
5,
|
||||
19,
|
||||
18,
|
||||
16,
|
||||
17,
|
||||
]
|
||||
|
||||
# 打开混淆图像
|
||||
img = Image.open(input_path)
|
||||
new_img = Image.new("RGB", (260,160))
|
||||
new_img = Image.new("RGB", (260, 160))
|
||||
r = 160
|
||||
for _ in range(len(Ut)):
|
||||
a = r / 2
|
||||
@@ -63,11 +114,12 @@ def restore_geetest_image(input_path:str, output_path:str) -> None:
|
||||
new_img.save(output_path)
|
||||
logger.debug("图像已还原并保存到: {}", output_path)
|
||||
|
||||
|
||||
# 下载图片
|
||||
def download_picture(bg:str, fullbg:str, slice:str) -> int:
|
||||
def download_picture(bg: str, fullbg: str, slice: str) -> int:
|
||||
for i in range(3):
|
||||
if i == 0:
|
||||
url = "https://static.geetest.com/"+bg
|
||||
url = "https://static.geetest.com/" + bg
|
||||
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
with open("bg.jpg", "wb") as f:
|
||||
@@ -87,4 +139,4 @@ def download_picture(bg:str, fullbg:str, slice:str) -> int:
|
||||
response.raise_for_status()
|
||||
with open("slice.jpg", "wb") as f:
|
||||
f.write(response.content)
|
||||
return shibie(Image.open('fullbg.jpg'), Image.open('slice.jpg'))
|
||||
return shibie(Image.open("fullbg.jpg"), Image.open("slice.jpg"))
|
||||
|
||||
+173
-143
@@ -29,13 +29,15 @@ def _get(
|
||||
def _parse_jsonp_response(response: requests.Response, source: str) -> dict:
|
||||
"""解析极验 JSONP 响应。"""
|
||||
response.raise_for_status()
|
||||
match = re.search(r'\((.*)\)$', response.text)
|
||||
match = re.search(r"\((.*)\)$", response.text)
|
||||
if not match:
|
||||
raise ValueError(f"{source} 无法解析 JSONP 响应")
|
||||
|
||||
data = json.loads(match.group(1))
|
||||
if data.get('status') == 'error':
|
||||
raise ValueError(f"{source} 失败: {data.get('user_error', data.get('error', '未知错误'))}")
|
||||
if data.get("status") == "error":
|
||||
raise ValueError(
|
||||
f"{source} 失败: {data.get('user_error', data.get('error', '未知错误'))}"
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
@@ -55,26 +57,26 @@ def _parse_json_response(response: requests.Response, source: str) -> dict:
|
||||
|
||||
def get_challenge_gt_bak() -> Tuple[str, str]:
|
||||
headers = {
|
||||
'accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'accept-language': 'zh-CN,zh;q=0.9',
|
||||
'priority': 'u=1, i',
|
||||
'referer': 'https://demos.geetest.com/slide-float.html',
|
||||
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
|
||||
'x-requested-with': 'XMLHttpRequest',
|
||||
"accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"priority": "u=1, i",
|
||||
"referer": "https://demos.geetest.com/slide-float.html",
|
||||
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
}
|
||||
|
||||
params = {
|
||||
't': str(int(round(time.time() * 1000))),
|
||||
"t": str(int(round(time.time() * 1000))),
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
'https://demos.geetest.com/gt/register-slide',
|
||||
"https://demos.geetest.com/gt/register-slide",
|
||||
params=params,
|
||||
headers=headers,
|
||||
timeout=10,
|
||||
@@ -85,21 +87,21 @@ def get_challenge_gt_bak() -> Tuple[str, str]:
|
||||
|
||||
def get_challenge_gt() -> Tuple[str, str]:
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'referer': 'https://passport.douyu.com/member/login?state=https%3A%2F%2Fwww.douyu.com%2Fmember%2FcpSecurity%2Fcheck_geetest_status',
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
|
||||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"referer": "https://passport.douyu.com/member/login?state=https%3A%2F%2Fwww.douyu.com%2Fmember%2FcpSecurity%2Fcheck_geetest_status",
|
||||
}
|
||||
|
||||
data = {
|
||||
'type': '1',
|
||||
'nicknameOrPhoneEncrypt': '03ILaBwtmmCm0A==',
|
||||
'password': '57219dddec71c31b7647683fa5306103',
|
||||
'biz_type': '1',
|
||||
"type": "1",
|
||||
"nicknameOrPhoneEncrypt": "03ILaBwtmmCm0A==",
|
||||
"password": "57219dddec71c31b7647683fa5306103",
|
||||
"biz_type": "1",
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
'https://passport.douyu.com/wgapi/member/passport/login',
|
||||
"https://passport.douyu.com/wgapi/member/passport/login",
|
||||
headers=headers,
|
||||
data=data,
|
||||
timeout=10,
|
||||
@@ -114,28 +116,27 @@ def get_challenge_gt() -> Tuple[str, str]:
|
||||
raise ValueError(f"斗鱼登录接口返回中缺少极验参数: {preview}") from exc
|
||||
|
||||
|
||||
|
||||
def get_js_address(gt: str, proxies: Optional[Mapping[str, str]] = None) -> dict:
|
||||
headers = {
|
||||
'accept': '*/*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9',
|
||||
'referer': PASSPORT_REFERER,
|
||||
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"macOS"',
|
||||
'sec-fetch-dest': 'script',
|
||||
'sec-fetch-mode': 'no-cors',
|
||||
'sec-fetch-site': 'cross-site',
|
||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
|
||||
"accept": "*/*",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"referer": PASSPORT_REFERER,
|
||||
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"macOS"',
|
||||
"sec-fetch-dest": "script",
|
||||
"sec-fetch-mode": "no-cors",
|
||||
"sec-fetch-site": "cross-site",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
}
|
||||
|
||||
params = {
|
||||
'gt': gt,
|
||||
'callback': 'geetest_' + str(int(round(time.time() * 1000))),
|
||||
"gt": gt,
|
||||
"callback": "geetest_" + str(int(round(time.time() * 1000))),
|
||||
}
|
||||
|
||||
response = _get(
|
||||
'https://api.geetest.com/gettype.php',
|
||||
"https://api.geetest.com/gettype.php",
|
||||
params=params,
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
@@ -143,6 +144,7 @@ def get_js_address(gt: str, proxies: Optional[Mapping[str, str]] = None) -> dict
|
||||
|
||||
return _parse_jsonp_response(response, "极验 gettype")
|
||||
|
||||
|
||||
def get_c_s(
|
||||
gt: str,
|
||||
challenge: str,
|
||||
@@ -150,26 +152,32 @@ def get_c_s(
|
||||
proxies: Optional[Mapping[str, str]] = None,
|
||||
) -> Tuple[list[int], str]:
|
||||
headers = {
|
||||
'accept': '*/*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9',
|
||||
'referer': PASSPORT_REFERER,
|
||||
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"macOS"',
|
||||
'sec-fetch-dest': 'script',
|
||||
'sec-fetch-mode': 'no-cors',
|
||||
'sec-fetch-site': 'cross-site',
|
||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
|
||||
"accept": "*/*",
|
||||
"accept-language": "zh-CN,zh;q=0.9",
|
||||
"referer": PASSPORT_REFERER,
|
||||
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"macOS"',
|
||||
"sec-fetch-dest": "script",
|
||||
"sec-fetch-mode": "no-cors",
|
||||
"sec-fetch-site": "cross-site",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
}
|
||||
|
||||
response = _get(
|
||||
'https://api.geetest.com/get.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w + '&callback=geetest_' + str(
|
||||
int(round(time.time() * 1000))),
|
||||
"https://api.geetest.com/get.php?gt="
|
||||
+ gt
|
||||
+ "&challenge="
|
||||
+ challenge
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
)
|
||||
data = _parse_jsonp_response(response, "极验 get.php")
|
||||
return data['data']['c'], data['data']['s']
|
||||
return data["data"]["c"], data["data"]["s"]
|
||||
|
||||
|
||||
def req_fullpage_validate(
|
||||
@@ -180,159 +188,181 @@ def req_fullpage_validate(
|
||||
) -> dict:
|
||||
"""HAR 中的 fullpage 最终校验,成功后直接返回 validate。"""
|
||||
headers = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'Referer': PASSPORT_REFERER,
|
||||
'Sec-Fetch-Dest': 'script',
|
||||
'Sec-Fetch-Mode': 'no-cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
|
||||
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"macOS"',
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": PASSPORT_REFERER,
|
||||
"Sec-Fetch-Dest": "script",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"macOS"',
|
||||
}
|
||||
|
||||
response = _get(
|
||||
'https://api.geetest.com/ajax.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w + '&callback=geetest_' + str(
|
||||
int(round(time.time() * 1000))),
|
||||
"https://api.geetest.com/ajax.php?gt="
|
||||
+ gt
|
||||
+ "&challenge="
|
||||
+ challenge
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
)
|
||||
return _parse_jsonp_response(response, "极验 fullpage ajax.php")
|
||||
|
||||
def req_slide(gt:str, challenge:str, w2:str) -> None:
|
||||
|
||||
def req_slide(gt: str, challenge: str, w2: str) -> None:
|
||||
headers = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'Referer': 'https://demos.geetest.com/',
|
||||
'Sec-Fetch-Dest': 'script',
|
||||
'Sec-Fetch-Mode': 'no-cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'Sec-Fetch-Storage-Access': 'active',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
|
||||
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": "https://demos.geetest.com/",
|
||||
"Sec-Fetch-Dest": "script",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-Storage-Access": "active",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
'https://api.geevisit.com/ajax.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w2 + '&callback=geetest_' + str(
|
||||
int(round(time.time() * 1000))),
|
||||
"https://api.geevisit.com/ajax.php?gt="
|
||||
+ gt
|
||||
+ "&challenge="
|
||||
+ challenge
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w2
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
headers=headers,
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
def get_picture(gt:str, challenge:str) -> tuple[str, str, list[int], str, str, str]:
|
||||
|
||||
def get_picture(gt: str, challenge: str) -> tuple[str, str, list[int], str, str, str]:
|
||||
headers = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'Referer': 'https://demos.geetest.com/',
|
||||
'Sec-Fetch-Dest': 'script',
|
||||
'Sec-Fetch-Mode': 'no-cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'Sec-Fetch-Storage-Access': 'active',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
|
||||
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": "https://demos.geetest.com/",
|
||||
"Sec-Fetch-Dest": "script",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-Storage-Access": "active",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
}
|
||||
params = {
|
||||
'is_next': 'true',
|
||||
'type': 'slide3',
|
||||
'gt': gt,
|
||||
'challenge': challenge,
|
||||
'lang': 'zh-cn',
|
||||
'https': 'true',
|
||||
'protocol': 'https://',
|
||||
'offline': 'false',
|
||||
'product': 'embed',
|
||||
'api_server': 'api.geevisit.com',
|
||||
'isPC': 'true',
|
||||
'autoReset': 'true',
|
||||
'width': '100%',
|
||||
'callback': 'geetest_'+str(int(round(time.time() * 1000))),
|
||||
"is_next": "true",
|
||||
"type": "slide3",
|
||||
"gt": gt,
|
||||
"challenge": challenge,
|
||||
"lang": "zh-cn",
|
||||
"https": "true",
|
||||
"protocol": "https://",
|
||||
"offline": "false",
|
||||
"product": "embed",
|
||||
"api_server": "api.geevisit.com",
|
||||
"isPC": "true",
|
||||
"autoReset": "true",
|
||||
"width": "100%",
|
||||
"callback": "geetest_" + str(int(round(time.time() * 1000))),
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
'https://api.geevisit.com/get.php',
|
||||
"https://api.geevisit.com/get.php",
|
||||
params=params,
|
||||
headers=headers,
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.debug("极验 get.php 原始响应: {}", response.text[:500])
|
||||
match = re.search(r'\((.*)\)$', response.text)
|
||||
match = re.search(r"\((.*)\)$", response.text)
|
||||
if match:
|
||||
json_str = match.group(1)
|
||||
data = json.loads(json_str)
|
||||
|
||||
if 'data' in data and isinstance(data['data'], dict):
|
||||
if "data" in data and isinstance(data["data"], dict):
|
||||
# 新版极验格式
|
||||
inner_data = data['data']
|
||||
inner_data = data["data"]
|
||||
return (
|
||||
inner_data.get('bg', ''),
|
||||
inner_data.get('fullbg', ''),
|
||||
inner_data.get('c', []),
|
||||
inner_data.get('s', ''),
|
||||
inner_data.get('slice', ''),
|
||||
inner_data.get('challenge', '')
|
||||
inner_data.get("bg", ""),
|
||||
inner_data.get("fullbg", ""),
|
||||
inner_data.get("c", []),
|
||||
inner_data.get("s", ""),
|
||||
inner_data.get("slice", ""),
|
||||
inner_data.get("challenge", ""),
|
||||
)
|
||||
else:
|
||||
# 旧版极验格式
|
||||
return (
|
||||
data.get('bg', ''),
|
||||
data.get('fullbg', ''),
|
||||
data.get('c', []),
|
||||
data.get('s', ''),
|
||||
data.get('slice', ''),
|
||||
data.get('challenge', '')
|
||||
data.get("bg", ""),
|
||||
data.get("fullbg", ""),
|
||||
data.get("c", []),
|
||||
data.get("s", ""),
|
||||
data.get("slice", ""),
|
||||
data.get("challenge", ""),
|
||||
)
|
||||
else:
|
||||
raise ValueError("无法解析 JSONP 响应")
|
||||
|
||||
def req_end(gt:str, challenge:str, w:str) -> dict:
|
||||
|
||||
def req_end(gt: str, challenge: str, w: str) -> dict:
|
||||
|
||||
headers = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'Referer': 'https://demos.geetest.com/',
|
||||
'Sec-Fetch-Dest': 'script',
|
||||
'Sec-Fetch-Mode': 'no-cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'Sec-Fetch-Storage-Access': 'active',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
|
||||
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": "https://demos.geetest.com/",
|
||||
"Sec-Fetch-Dest": "script",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-Storage-Access": "active",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
'https://api.geevisit.com/ajax.php?gt='+gt+'&challenge='+challenge+'&lang=zh-cn&%24_BCm=0&client_type=web&w='+w+'&callback=geetest_'+str(int(round(time.time() * 1000))),
|
||||
"https://api.geevisit.com/ajax.php?gt="
|
||||
+ gt
|
||||
+ "&challenge="
|
||||
+ challenge
|
||||
+ "&lang=zh-cn&%24_BCm=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
headers=headers,
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.debug("极验 ajax.php 原始响应: {}", response.text[:500])
|
||||
match = re.search(r'\((.*)\)$', response.text)
|
||||
match = re.search(r"\((.*)\)$", response.text)
|
||||
if match:
|
||||
json_str = match.group(1)
|
||||
data = json.loads(json_str)
|
||||
logger.debug("极验验证响应: {}", data)
|
||||
|
||||
# 检查验证是否成功
|
||||
if data.get('success') == 1:
|
||||
if data.get("success") == 1:
|
||||
return data
|
||||
else:
|
||||
# 如果验证失败,返回错误信息
|
||||
return {
|
||||
'success': 0,
|
||||
'message': data.get('message', '验证失败'),
|
||||
'validate': ''
|
||||
"success": 0,
|
||||
"message": data.get("message", "验证失败"),
|
||||
"validate": "",
|
||||
}
|
||||
else:
|
||||
raise ValueError("无法解析 JSONP 响应")
|
||||
|
||||
@@ -18,63 +18,70 @@ def generate_fake_performance_timing(base_time: Optional[int] = None) -> dict[st
|
||||
|
||||
# 定义合理的时间间隔范围(毫秒)
|
||||
intervals = {
|
||||
'fetch': random.randint(1, 2),
|
||||
'domain_lookup_start': random.randint(3, 5),
|
||||
'domain_lookup': random.randint(5, 15),
|
||||
'connect': random.randint(50, 150),
|
||||
'ssl_offset': random.randint(30, 50),
|
||||
'request': random.randint(1, 5),
|
||||
'response': random.randint(20, 100),
|
||||
'response_end': random.randint(1, 3),
|
||||
'unload_start': random.randint(1, 3),
|
||||
'unload': random.randint(1, 5),
|
||||
'dom_loading': random.randint(1, 3),
|
||||
'dom_interactive': random.randint(50, 200),
|
||||
'dom_content_loaded': random.randint(1, 3),
|
||||
'load_event': random.randint(0, 5)
|
||||
"fetch": random.randint(1, 2),
|
||||
"domain_lookup_start": random.randint(3, 5),
|
||||
"domain_lookup": random.randint(5, 15),
|
||||
"connect": random.randint(50, 150),
|
||||
"ssl_offset": random.randint(30, 50),
|
||||
"request": random.randint(1, 5),
|
||||
"response": random.randint(20, 100),
|
||||
"response_end": random.randint(1, 3),
|
||||
"unload_start": random.randint(1, 3),
|
||||
"unload": random.randint(1, 5),
|
||||
"dom_loading": random.randint(1, 3),
|
||||
"dom_interactive": random.randint(50, 200),
|
||||
"dom_content_loaded": random.randint(1, 3),
|
||||
"load_event": random.randint(0, 5),
|
||||
}
|
||||
|
||||
timing = {}
|
||||
|
||||
# 按照时间顺序构建
|
||||
timing['navigationStart'] = base_time
|
||||
timing['fetchStart'] = timing['navigationStart'] + intervals['fetch']
|
||||
timing['domainLookupStart'] = timing['fetchStart'] + intervals['domain_lookup_start']
|
||||
timing['domainLookupEnd'] = timing['domainLookupStart'] + intervals['domain_lookup']
|
||||
timing["navigationStart"] = base_time
|
||||
timing["fetchStart"] = timing["navigationStart"] + intervals["fetch"]
|
||||
timing["domainLookupStart"] = (
|
||||
timing["fetchStart"] + intervals["domain_lookup_start"]
|
||||
)
|
||||
timing["domainLookupEnd"] = timing["domainLookupStart"] + intervals["domain_lookup"]
|
||||
|
||||
timing['connectStart'] = timing['domainLookupEnd']
|
||||
timing['secureConnectionStart'] = timing['connectStart'] + intervals['ssl_offset']
|
||||
timing['connectEnd'] = timing['connectStart'] + intervals['connect']
|
||||
timing["connectStart"] = timing["domainLookupEnd"]
|
||||
timing["secureConnectionStart"] = timing["connectStart"] + intervals["ssl_offset"]
|
||||
timing["connectEnd"] = timing["connectStart"] + intervals["connect"]
|
||||
|
||||
timing['requestStart'] = timing['connectEnd'] + intervals['request']
|
||||
timing['responseStart'] = timing['requestStart'] + intervals['response']
|
||||
timing['responseEnd'] = timing['responseStart'] + intervals['response_end']
|
||||
timing["requestStart"] = timing["connectEnd"] + intervals["request"]
|
||||
timing["responseStart"] = timing["requestStart"] + intervals["response"]
|
||||
timing["responseEnd"] = timing["responseStart"] + intervals["response_end"]
|
||||
|
||||
timing['unloadEventStart'] = timing['responseEnd'] + intervals['unload_start']
|
||||
timing['unloadEventEnd'] = timing['unloadEventStart'] + intervals['unload']
|
||||
timing["unloadEventStart"] = timing["responseEnd"] + intervals["unload_start"]
|
||||
timing["unloadEventEnd"] = timing["unloadEventStart"] + intervals["unload"]
|
||||
|
||||
timing['domLoading'] = timing['unloadEventEnd'] + intervals['dom_loading']
|
||||
timing['domInteractive'] = timing['domLoading'] + intervals['dom_interactive']
|
||||
timing['domContentLoadedEventStart'] = timing['domInteractive']
|
||||
timing['domContentLoadedEventEnd'] = timing['domInteractive'] + intervals['dom_content_loaded']
|
||||
timing['domComplete'] = timing['domContentLoadedEventEnd']
|
||||
timing['loadEventStart'] = timing['domComplete']
|
||||
timing['loadEventEnd'] = timing['loadEventStart'] + intervals['load_event']
|
||||
timing["domLoading"] = timing["unloadEventEnd"] + intervals["dom_loading"]
|
||||
timing["domInteractive"] = timing["domLoading"] + intervals["dom_interactive"]
|
||||
timing["domContentLoadedEventStart"] = timing["domInteractive"]
|
||||
timing["domContentLoadedEventEnd"] = (
|
||||
timing["domInteractive"] + intervals["dom_content_loaded"]
|
||||
)
|
||||
timing["domComplete"] = timing["domContentLoadedEventEnd"]
|
||||
timing["loadEventStart"] = timing["domComplete"]
|
||||
timing["loadEventEnd"] = timing["loadEventStart"] + intervals["load_event"]
|
||||
|
||||
# 无重定向的情况
|
||||
timing['redirectStart'] = 0
|
||||
timing['redirectEnd'] = 0
|
||||
timing["redirectStart"] = 0
|
||||
timing["redirectEnd"] = 0
|
||||
|
||||
return timing
|
||||
|
||||
|
||||
def __ease_out_expo(sep):
|
||||
'''
|
||||
轨迹相关操作
|
||||
'''
|
||||
"""
|
||||
轨迹相关操作
|
||||
"""
|
||||
if sep == 1:
|
||||
return 1
|
||||
else:
|
||||
return 1 - pow(2, -10 * sep)
|
||||
|
||||
|
||||
def get_slide_track(distance):
|
||||
"""
|
||||
根据滑动距离生成滑动轨迹
|
||||
@@ -86,7 +93,9 @@ def get_slide_track(distance):
|
||||
"""
|
||||
|
||||
if not isinstance(distance, int) or distance < 0:
|
||||
raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
|
||||
raise ValueError(
|
||||
f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}"
|
||||
)
|
||||
# 初始化轨迹列表
|
||||
slide_track = [
|
||||
[random.randint(-50, -10), random.randint(-50, -10), 0],
|
||||
@@ -110,4 +119,4 @@ def get_slide_track(distance):
|
||||
slide_track.append([x, _y, t])
|
||||
_x = x
|
||||
slide_track.append(slide_track[-1])
|
||||
return slide_track, slide_track[-1][2]
|
||||
return slide_track, slide_track[-1][2]
|
||||
|
||||
@@ -2,25 +2,60 @@ import time
|
||||
import random
|
||||
import json
|
||||
from loguru import logger
|
||||
from core.geetest.common.trajectory import generate_realistic_trajectory, process_mouse_trajectory, compress_trajectory, TrajectoryEncoder, \
|
||||
H
|
||||
from core.geetest.common.crypto import four_random_chart, RSA_jiami_r, AES_O, geetest_base64_encode, encrypt_string, simple_md5
|
||||
from core.geetest.common.trajectory import (
|
||||
generate_realistic_trajectory,
|
||||
process_mouse_trajectory,
|
||||
compress_trajectory,
|
||||
TrajectoryEncoder,
|
||||
H,
|
||||
)
|
||||
from core.geetest.common.crypto import (
|
||||
four_random_chart,
|
||||
RSA_jiami_r,
|
||||
AES_O,
|
||||
geetest_base64_encode,
|
||||
encrypt_string,
|
||||
simple_md5,
|
||||
)
|
||||
from core.geetest.common.imaging import download_picture
|
||||
from core.geetest.common.network import get_challenge_gt, get_js_address, get_c_s, req_slide, get_picture, req_end
|
||||
from core.geetest.common.performance import generate_fake_performance_timing, get_slide_track
|
||||
from core.geetest.common.network import (
|
||||
get_challenge_gt,
|
||||
get_js_address,
|
||||
get_c_s,
|
||||
req_slide,
|
||||
get_picture,
|
||||
req_end,
|
||||
)
|
||||
from core.geetest.common.performance import (
|
||||
generate_fake_performance_timing,
|
||||
get_slide_track,
|
||||
)
|
||||
|
||||
|
||||
def _generate_seed() -> str:
|
||||
return four_random_chart() + four_random_chart() + four_random_chart() + four_random_chart()
|
||||
return (
|
||||
four_random_chart()
|
||||
+ four_random_chart()
|
||||
+ four_random_chart()
|
||||
+ four_random_chart()
|
||||
)
|
||||
|
||||
def get_w1(gt:str, challenge:str, str_16:str) -> str:
|
||||
|
||||
def get_w1(gt: str, challenge: str, str_16: str) -> str:
|
||||
r = RSA_jiami_r(str_16)
|
||||
plaintext = '{"gt":"' + gt + '","challenge":"' + challenge + '","offline":false,"new_captcha":true,"product":"float","width":"300px","https":true,"api_server":"apiv6.geetest.com","protocol":"https://","type":"fullpage","static_servers":["static.geetest.com/","static.geevisit.com/"],"voice":"/static/js/voice.1.2.6.js","click":"/static/js/click.3.1.2.js","beeline":"/static/js/beeline.1.0.1.js","fullpage":"/static/js/fullpage.9.2.0-guwyxh.js","slide":"/static/js/slide.7.9.3.js","geetest":"/static/js/geetest.6.0.9.js","aspect_radio":{"slide":103,"click":128,"voice":128,"beeline":50},"cc":16,"ww":true,"i":"-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1"}'
|
||||
plaintext = (
|
||||
'{"gt":"'
|
||||
+ gt
|
||||
+ '","challenge":"'
|
||||
+ challenge
|
||||
+ '","offline":false,"new_captcha":true,"product":"float","width":"300px","https":true,"api_server":"apiv6.geetest.com","protocol":"https://","type":"fullpage","static_servers":["static.geetest.com/","static.geevisit.com/"],"voice":"/static/js/voice.1.2.6.js","click":"/static/js/click.3.1.2.js","beeline":"/static/js/beeline.1.0.1.js","fullpage":"/static/js/fullpage.9.2.0-guwyxh.js","slide":"/static/js/slide.7.9.3.js","geetest":"/static/js/geetest.6.0.9.js","aspect_radio":{"slide":103,"click":128,"voice":128,"beeline":50},"cc":16,"ww":true,"i":"-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1"}'
|
||||
)
|
||||
o = AES_O(plaintext, str_16)
|
||||
i = geetest_base64_encode(o)
|
||||
return i['res'] + i['end'] + r
|
||||
return i["res"] + i["end"] + r
|
||||
|
||||
def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
|
||||
|
||||
def get_w2(gt: str, challenge: str, c: list[int], s: str, str_16: str) -> str:
|
||||
# 伪造浏览器性能数据
|
||||
fake_timing = generate_fake_performance_timing()
|
||||
# 映射
|
||||
@@ -45,7 +80,7 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
|
||||
"r": fake_timing["domContentLoadedEventEnd"],
|
||||
"s": fake_timing["domComplete"],
|
||||
"t": fake_timing["loadEventStart"],
|
||||
"u": fake_timing["loadEventEnd"]
|
||||
"u": fake_timing["loadEventEnd"],
|
||||
}
|
||||
|
||||
first_time = int(round(time.time() * 1000)) # 伪造脚本开始运行时间
|
||||
@@ -55,10 +90,9 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
|
||||
start_y=random.randint(400, 500),
|
||||
end_x=853,
|
||||
end_y=288,
|
||||
start_time=first_time
|
||||
start_time=first_time,
|
||||
)
|
||||
|
||||
|
||||
trajectory = process_mouse_trajectory(guiji_yuanshu_shuzu)["data"]
|
||||
compressed = compress_trajectory(trajectory)
|
||||
tt = encrypt_string(compressed, c, s)
|
||||
@@ -67,14 +101,30 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
|
||||
|
||||
rp = simple_md5(gt + challenge + passtime)
|
||||
|
||||
plaintext = '{"lang":"zh-cn","type":"fullpage","tt":"'+tt+'","light":"DIV_0","s":"c7c3e21112fe4f741921cb3e4ff9f7cb","h":"321f9af1e098233dbd03f250fd2b5e21","hh":"39bd9cad9e425c3a8f51610fd506e3b3","hi":"09eb21b3ae9542a9bc1e8b63b3d9a467","vip_order":-1,"ct":-1,"ep":{"v":"9.2.0-guwyxh","te":false,"$_BBn":true,"ven":"Google Inc. (AMD)","ren":"ANGLE (AMD, AMD Radeon RX 6750 GRE 12GB (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)","fp":'+json.dumps(guiji_yuanshu_shuzu[0], separators=(',', ':'))+',"lp":'+json.dumps(guiji_yuanshu_shuzu[-1], separators=(',', ':'))+',"em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0},"tm":'+json.dumps(web_load_time, separators=(',', ':'))+',"dnf":"dnf","by":0},"passtime":'+passtime+',"rp":"'+rp+'","captcha_token":"112439067","tsfq":"xovrayel"}'
|
||||
|
||||
plaintext = (
|
||||
'{"lang":"zh-cn","type":"fullpage","tt":"'
|
||||
+ tt
|
||||
+ '","light":"DIV_0","s":"c7c3e21112fe4f741921cb3e4ff9f7cb","h":"321f9af1e098233dbd03f250fd2b5e21","hh":"39bd9cad9e425c3a8f51610fd506e3b3","hi":"09eb21b3ae9542a9bc1e8b63b3d9a467","vip_order":-1,"ct":-1,"ep":{"v":"9.2.0-guwyxh","te":false,"$_BBn":true,"ven":"Google Inc. (AMD)","ren":"ANGLE (AMD, AMD Radeon RX 6750 GRE 12GB (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)","fp":'
|
||||
+ json.dumps(guiji_yuanshu_shuzu[0], separators=(",", ":"))
|
||||
+ ',"lp":'
|
||||
+ json.dumps(guiji_yuanshu_shuzu[-1], separators=(",", ":"))
|
||||
+ ',"em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0},"tm":'
|
||||
+ json.dumps(web_load_time, separators=(",", ":"))
|
||||
+ ',"dnf":"dnf","by":0},"passtime":'
|
||||
+ passtime
|
||||
+ ',"rp":"'
|
||||
+ rp
|
||||
+ '","captcha_token":"112439067","tsfq":"xovrayel"}'
|
||||
)
|
||||
|
||||
result = geetest_base64_encode(AES_O(plaintext, str_16))
|
||||
|
||||
return result['res']+result['end']+result['end']
|
||||
return result["res"] + result["end"] + result["end"]
|
||||
|
||||
def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> str:
|
||||
|
||||
def get_w3(
|
||||
str_16: str, challenge: str, hkjl: int, c: list[int], s: str, gt: str
|
||||
) -> str:
|
||||
encoder = TrajectoryEncoder()
|
||||
u = RSA_jiami_r(str_16)
|
||||
# 伪造浏览器性能数据
|
||||
@@ -101,11 +151,9 @@ def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> s
|
||||
"r": fake_timing["domContentLoadedEventEnd"],
|
||||
"s": fake_timing["domComplete"],
|
||||
"t": fake_timing["loadEventStart"],
|
||||
"u": fake_timing["loadEventEnd"]
|
||||
"u": fake_timing["loadEventEnd"],
|
||||
}
|
||||
|
||||
|
||||
|
||||
trajectory = get_slide_track(hkjl)[0]
|
||||
logger.debug("滑动轨迹: {}", trajectory)
|
||||
|
||||
@@ -117,13 +165,25 @@ def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> s
|
||||
|
||||
passtime = str(trajectory[-1][2])
|
||||
|
||||
|
||||
rp = simple_md5(gt + challenge[:32] + passtime)
|
||||
|
||||
plaintext = '{"lang":"zh-cn","userresponse":"'+userresponse+'","passtime":'+passtime+',"imgload":50,"aa":"'+aa+'","ep":{"v":"7.9.3","$_BIT":false,"me":true,"tm":'+json.dumps(web_load_time, separators=(',', ':'))+',"td":-1},"h9s9":"1816378497","rp":"'+rp+'"}'
|
||||
plaintext = (
|
||||
'{"lang":"zh-cn","userresponse":"'
|
||||
+ userresponse
|
||||
+ '","passtime":'
|
||||
+ passtime
|
||||
+ ',"imgload":50,"aa":"'
|
||||
+ aa
|
||||
+ '","ep":{"v":"7.9.3","$_BIT":false,"me":true,"tm":'
|
||||
+ json.dumps(web_load_time, separators=(",", ":"))
|
||||
+ ',"td":-1},"h9s9":"1816378497","rp":"'
|
||||
+ rp
|
||||
+ '"}'
|
||||
)
|
||||
|
||||
h = geetest_base64_encode(AES_O(plaintext, str_16))["res"]
|
||||
return h + u
|
||||
|
||||
h = geetest_base64_encode(AES_O(plaintext, str_16))['res']
|
||||
return h+u
|
||||
|
||||
def run_solver() -> None:
|
||||
# 16位字符串
|
||||
@@ -154,7 +214,7 @@ def run_solver() -> None:
|
||||
hkjl = download_picture(bg, fullbg, slice)
|
||||
|
||||
# 获取第三个w值
|
||||
w3 = get_w3(str_16,challenge,hkjl,c,s,gt)
|
||||
w3 = get_w3(str_16, challenge, hkjl, c, s, gt)
|
||||
|
||||
# 最后的验证
|
||||
message = req_end(gt, challenge, w3)
|
||||
|
||||
Reference in New Issue
Block a user