geetest_crack.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import ddddocr
  2. from PIL import Image
  3. import io
  4. import numpy as np
  5. import time
  6. import json
  7. import base64
  8. import random
  9. import math
  10. import requests
  11. import urllib.parse
  12. class TDCSimulator:
  13. def __init__(self):
  14. self.start_time = int(time.time() * 1000)
  15. self.data = {
  16. "tdf": 1,
  17. "ts": [],
  18. "points": [],
  19. "events": [],
  20. "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  21. "tm": {
  22. "st": self.start_time,
  23. "ed": 0
  24. }
  25. }
  26. def add_point(self, x, y, t):
  27. self.data["points"].append([x, y])
  28. self.data["ts"].append(t - self.start_time)
  29. def add_event(self, type_, x, y):
  30. t = int(time.time() * 1000) - self.start_time
  31. self.data["events"].append({
  32. "type": type_,
  33. "t": t,
  34. "x": x,
  35. "y": y
  36. })
  37. def get_data(self):
  38. self.data["tm"]["ed"] = int(time.time() * 1000)
  39. return base64.b64encode(json.dumps(self.data).encode()).decode()
  40. def generate_tracks(start_pos, target_pos):
  41. tracks = []
  42. distance = target_pos[0] - start_pos[0]
  43. current = 0
  44. t = int(time.time() * 1000)
  45. v = 0 # 初始速度
  46. x = start_pos[0]
  47. y = start_pos[1]
  48. while current < distance:
  49. delta_t = 10 # 10ms
  50. t += delta_t
  51. # 加速阶段
  52. if current < distance * 0.6:
  53. v += (random.random() * 2 + 2)
  54. # 减速阶段
  55. else:
  56. v *= 0.98
  57. # 位移
  58. delta_x = v * (delta_t / 1000)
  59. current += delta_x
  60. x += delta_x
  61. # y轴抖动
  62. y = start_pos[1] + (random.random() * 2 - 1)
  63. tracks.append({
  64. "x": round(x),
  65. "y": round(y),
  66. "t": t
  67. })
  68. # 确保最后到达目标位置
  69. tracks.append({
  70. "x": target_pos[0],
  71. "y": target_pos[1],
  72. "t": t + 10
  73. })
  74. return tracks
  75. def get_collect(start_pos, target_pos):
  76. tdc = TDCSimulator()
  77. # 开始事件
  78. tdc.add_event("start", start_pos[0], start_pos[1])
  79. # 按下事件
  80. tdc.add_event("down", start_pos[0], start_pos[1])
  81. # 移动轨迹
  82. tracks = generate_tracks(start_pos, target_pos)
  83. for track in tracks:
  84. tdc.add_point(track["x"], track["y"], track["t"])
  85. # 松开事件
  86. tdc.add_event("up", target_pos[0], target_pos[1])
  87. # 结束事件
  88. tdc.add_event("end", target_pos[0], target_pos[1])
  89. return tdc.get_data()
  90. def get_gap(target_img:bytes, background_img:bytes):
  91. det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
  92. res = det.slide_match(target_img, background_img,simple_target=True)
  93. print(res)
  94. return res["target"][0]
  95. def parse_positions(data):
  96. """
  97. 解析验证码位置信息
  98. 参数:
  99. data: _aq_88765 返回的数据
  100. 返回:
  101. {
  102. "start_pos": [x, y],
  103. "move_limit": [min_x, max_x],
  104. "sess": session_id,
  105. "image_urls": {
  106. "bg": background_image_url,
  107. "sprite": sprite_image_url
  108. }
  109. }
  110. """
  111. try:
  112. # 获取滑块信息
  113. fg_elem_list = data["data"]["dyn_show_info"]["fg_elem_list"]
  114. slider_info = None
  115. for elem in fg_elem_list:
  116. if elem["id"] == 1: # id为1的元素是滑块
  117. slider_info = elem
  118. break
  119. if not slider_info:
  120. raise ValueError("未找到滑块信息")
  121. # 解析移动限制
  122. track_limit = slider_info["move_cfg"]["track_limit"] # "x>=50&&x<=552"
  123. limits = track_limit.replace("x>=", "").replace("&&x<=", ",").split(",")
  124. min_x = int(limits[0])
  125. max_x = int(limits[1])
  126. # 获取图片URL
  127. bg_img_url = data["data"]["dyn_show_info"]["bg_elem_cfg"]["img_url"]
  128. sprite_url = data["data"]["dyn_show_info"]["sprite_url"]
  129. # 获取session
  130. sess = data["sess"]
  131. return {
  132. "start_pos": slider_info["init_pos"], # [50, 226]
  133. "move_limit": [min_x, max_x], # [50, 552]
  134. "sess": sess,
  135. "image_urls": {
  136. "bg": bg_img_url,
  137. "sprite": sprite_url
  138. }
  139. }
  140. except Exception as e:
  141. print(f"解析位置信息失败: {str(e)}")
  142. return None
  143. def get_captcha_prehandle():
  144. # 基础URL
  145. base_url = "https://turing.captcha.qcloud.com/cap_union_prehandle"
  146. # 构造请求参数
  147. params = {
  148. "aid": "2026859470",
  149. "protocol": "https",
  150. "accver": "1",
  151. "showtype": "popup",
  152. "ua": "TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzEzMi4wLjAuMCBTYWZhcmkvNTM3",
  153. "noheader": "1",
  154. "fb": "1",
  155. "aged": "0",
  156. "enableAged": "0",
  157. "enableDarkMode": "0",
  158. "grayscale": "1",
  159. "clientype": "2",
  160. "cap_cd": "",
  161. "uid": "",
  162. "lang": "zh-cn",
  163. "entry_url": "https://open.yuewen.com/",
  164. "elder_captcha": "0",
  165. "js": "/tcaptcha-frame.c055d939.js",
  166. "login_appid": "",
  167. "wb": "1",
  168. "subsid": "5",
  169. "callback": "_aq_88765",
  170. "sess": ""
  171. }
  172. # 设置请求头
  173. headers = {
  174. "accept": "*/*",
  175. "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
  176. "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
  177. "sec-ch-ua-mobile": "?0",
  178. "sec-ch-ua-platform": '"Windows"',
  179. "sec-fetch-dest": "script",
  180. "sec-fetch-mode": "no-cors",
  181. "sec-fetch-site": "cross-site",
  182. "Referer": "https://open.yuewen.com/",
  183. "Referrer-Policy": "strict-origin-when-cross-origin"
  184. }
  185. try:
  186. # 发送GET请求
  187. response = requests.get(
  188. base_url,
  189. params=params,
  190. headers=headers
  191. )
  192. # 检查响应状态
  193. response.raise_for_status()
  194. # 获取响应文本
  195. return response.text
  196. except requests.exceptions.RequestException as e:
  197. print(f"请求失败: {str(e)}")
  198. return None
  199. # start_pos = [50, 226] # 滑块初始位置
  200. # target_pos = [342, 226] # 目标位置
  201. # collect = get_collect(start_pos, target_pos)
  202. # print(collect)