解密机大侠.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import requests
  2. import json
  3. from Crypto.Cipher import AES
  4. from Crypto.Util.Padding import unpad
  5. from typing import Optional, List, Dict, Any
  6. # --- 1. 解密函数 (从JS代码转换) ---
  7. def decrypt_order_data(hex_string):
  8. """
  9. 使用AES-CBC模式解密订单详情数据
  10. """
  11. key = b"S9u978T13NLCGc5W" # 密钥
  12. iv = b"X83yWMD9iKhLxfwX" # 偏移量 (IV)
  13. # 将十六进制字符串转换为字节
  14. encrypted_data = bytes.fromhex(hex_string)
  15. # 创建AES-CBC解密器
  16. cipher = AES.new(key, AES.MODE_CBC, iv)
  17. # 解密并去除填充 (PKCS7)
  18. decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
  19. # 返回UTF-8字符串
  20. return decrypted_data.decode('utf-8')
  21. # --- 2. 请求头配置 ---
  22. HEADERS = {
  23. 'Connection': 'keep-alive',
  24. 'content-type': 'application/json',
  25. 'Version': '2.50.0',
  26. 'timestamp': '1784094158706',
  27. 'Distinct-Id': '1784057137891-1059356-086b42dd38b0b98-24491897',
  28. 'vaccine': 'aa454c048e8843247cebf378d1a9a0fed759027f329caf68fd900654da4232d0',
  29. 'U-A': 'JiDaXiaWeApp/23958 (:)',
  30. 'x-version': 'ITC-77385',
  31. 'ahs-gate-language': 'zh_CN',
  32. 'APP-ID': 'jdx135624',
  33. 'platform': 'weapp',
  34. 'Register-Flow-Source': 'RECYCLER',
  35. 'ahs-language': 'zh-CN',
  36. 'access_token': 'jdx9ce52336abee4cf78db56567dc259512',
  37. 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 26_5_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.75(0x18004b3c) NetType/WIFI Language/zh_CN',
  38. 'Referer': 'https://servicewechat.com/wx7e6573879e91b1ac/28/page-frame.html',
  39. }
  40. # --- 3. 获取待抢订单列表 ---
  41. def get_pending_order_list(page_size: int = 10) -> Optional[List[Dict[str, Any]]]:
  42. """
  43. 获取待抢订单列表
  44. Args:
  45. page_size: 每页数量,默认10条
  46. Returns:
  47. 订单列表,失败返回None
  48. """
  49. url = "https://wirelessgate.aihuishou.com/jdx-rc-bff-service/app/order/pendingGrab/list"
  50. payload = {
  51. "pageSize": page_size,
  52. "status": -1,
  53. "isApplyForHandle": None,
  54. "applyPhotoStatus": None,
  55. "productIds": [265024, 225362, 225361, 225358, 225366, 173473, 161415, 161414, 161413, 161412, 121769, 121439, 121436, 121435, 98526, 98528, 98527, 98525, 43513, 43512, 43511, 43510, 36047, 36045, 36044, 36046, 32292, 32291, 32290, 27640, 27639, 27637, 25827, 25680, 25679, 23423, 23422, 66428, 34701, 20079, 17752, 17726, 17462, 17461, 17459, 17458, 17457, 17460, 17455, 2247, 2246],
  56. "sourceIds": None,
  57. "keyword": None,
  58. "timeObj": None,
  59. "rcOrderResult": None
  60. }
  61. try:
  62. response = requests.post(url, headers=HEADERS, json=payload)
  63. response.raise_for_status()
  64. result = response.json()
  65. if result.get('code') != 200:
  66. print(f"获取订单列表失败: {result.get('resultMessage', '未知错误')}")
  67. return None
  68. order_list = result.get('data', [])
  69. print(f"成功获取 {len(order_list)} 条待抢订单")
  70. return order_list
  71. except requests.RequestException as e:
  72. print(f"请求订单列表失败: {e}")
  73. return None
  74. except json.JSONDecodeError as e:
  75. print(f"解析订单列表JSON失败: {e}")
  76. return None
  77. # --- 4. 显示订单列表 ---
  78. def display_order_list(order_list: List[Dict[str, Any]]):
  79. """
  80. 美化显示订单列表
  81. """
  82. if not order_list:
  83. print("暂无待抢订单")
  84. return
  85. print("\n" + "="*80)
  86. print("待抢订单列表:")
  87. print("="*80)
  88. for idx, order in enumerate(order_list, 1):
  89. print(f"\n[{idx}] 订单号: {order.get('orderNo', 'N/A')}")
  90. print(f" 商品: {order.get('brandInfo', 'N/A')}")
  91. print(f" IMEI: {order.get('imei', 'N/A')}")
  92. print(f" 预估价格: {order.get('price', '待定')}")
  93. print(f" 门店: {order.get('title', 'N/A')}")
  94. print(f" 截止时间: {order.get('biddingDeadlineDt', 'N/A')}")
  95. # 显示标签
  96. labels = order.get('labels', [])
  97. if labels:
  98. label_names = [label.get('labelName', '') for label in labels]
  99. print(f" 标签: {', '.join(label_names)}")
  100. # 显示提示
  101. tips = order.get('tips', {})
  102. if tips:
  103. print(f" 提示: {tips.get('tipStr', 'N/A')}")
  104. print("\n" + "="*80)
  105. # --- 5. 从订单列表中提取订单号 ---
  106. def select_order_by_index(order_list: List[Dict[str, Any]], index: int) -> Optional[str]:
  107. """
  108. 根据索引从订单列表中提取订单号
  109. Args:
  110. order_list: 订单列表
  111. index: 索引(从1开始)
  112. Returns:
  113. 订单号,失败返回None
  114. """
  115. if not order_list:
  116. print("订单列表为空")
  117. return None
  118. if index < 1 or index > len(order_list):
  119. print(f"索引超出范围,请输入1-{len(order_list)}之间的数字")
  120. return None
  121. order_no = order_list[index - 1].get('orderNo')
  122. if not order_no:
  123. print(f"第{index}个订单缺少订单号")
  124. return None
  125. print(f"已选择订单: {order_no}")
  126. return order_no
  127. # --- 6. 获取订单详情(原有功能) ---
  128. def get_order_detail(order_no: str) -> Optional[Dict[str, Any]]:
  129. """
  130. 获取订单详情
  131. Args:
  132. order_no: 订单号
  133. Returns:
  134. 解密后的订单详情,失败返回None
  135. """
  136. # 第一步:获取BiddingNo
  137. snatch_url = "https://wirelessgate.aihuishou.com/jdx-rc-service/front/bid/snatch"
  138. snatch_payload = {"orderNo": order_no}
  139. print(f"\n正在获取订单 {order_no} 的BiddingNo...")
  140. try:
  141. snatch_response = requests.post(snatch_url, headers=HEADERS, json=snatch_payload)
  142. snatch_response.raise_for_status()
  143. snatch_data = snatch_response.json()
  144. if snatch_data.get('code') != 200:
  145. print(f"获取BiddingNo失败: {snatch_data.get('resultMessage', '未知错误')}")
  146. return None
  147. bidding_no = snatch_data.get('data')
  148. if not bidding_no:
  149. print("获取BiddingNo为空")
  150. return None
  151. print(f"成功获取 BiddingNo: {bidding_no}")
  152. except requests.RequestException as e:
  153. print(f"请求BiddingNo失败: {e}")
  154. return None
  155. except json.JSONDecodeError as e:
  156. print(f"解析BiddingNo响应失败: {e}")
  157. return None
  158. # 第二步:请求订单详情(加密数据)
  159. detail_url = f"https://wirelessgate.aihuishou.com/jdx-qa-service/app/ka/v3/order/detail?orderNo={order_no}&biddingNo={bidding_no}"
  160. print("正在请求订单详情...")
  161. try:
  162. detail_response = requests.get(detail_url, headers=HEADERS)
  163. detail_response.raise_for_status()
  164. detail_data = detail_response.json()
  165. if detail_data.get('code') != 200:
  166. print(f"请求订单详情失败: {detail_data.get('resultMessage', '未知错误')}")
  167. return None
  168. encrypted_hex = detail_data.get('data')
  169. if not encrypted_hex:
  170. print("未获取到加密数据")
  171. return None
  172. # 第三步:解密数据
  173. print("正在解密数据...")
  174. decrypted_json_string = decrypt_order_data(encrypted_hex)
  175. order_detail = json.loads(decrypted_json_string)
  176. return order_detail
  177. except requests.RequestException as e:
  178. print(f"请求订单详情失败: {e}")
  179. return None
  180. except json.JSONDecodeError as e:
  181. print(f"解析订单详情JSON失败: {e}")
  182. return None
  183. except Exception as e:
  184. print(f"解密或解析失败: {e}")
  185. return None
  186. # --- 7. 查找图片链接(原有功能) ---
  187. def find_original_image_by_notice(json_data, notice_keyword):
  188. """
  189. 在复杂的嵌套JSON中,根据notice字段的关键词查找并返回对应的originalImage链接
  190. """
  191. if isinstance(json_data, str):
  192. try:
  193. json_data = json.loads(json_data)
  194. except json.JSONDecodeError:
  195. print("错误:输入的字符串不是有效的JSON格式。")
  196. return None
  197. def recursive_search(obj):
  198. if isinstance(obj, dict):
  199. if 'notice' in obj and 'originalImage' in obj:
  200. if notice_keyword.lower() in obj['notice'].lower():
  201. return obj['originalImage']
  202. for value in obj.values():
  203. result = recursive_search(value)
  204. if result:
  205. return result
  206. elif isinstance(obj, list):
  207. for item in obj:
  208. result = recursive_search(item)
  209. if result:
  210. return result
  211. return None
  212. return recursive_search(json_data)
  213. # --- 8. 主流程(新增列表获取功能) ---
  214. def main():
  215. # 步骤1:获取待抢订单列表
  216. print("正在获取待抢订单列表...")
  217. order_list = get_pending_order_list(page_size=10)
  218. if not order_list:
  219. print("无法获取订单列表,程序退出")
  220. return
  221. # 步骤2:显示列表
  222. display_order_list(order_list)
  223. # 步骤3:让用户选择要查看的订单
  224. while True:
  225. try:
  226. choice = input("\n请输入要查看详情的订单序号 (1-{},输入0退出): ".format(len(order_list)))
  227. choice = int(choice.strip())
  228. if choice == 0:
  229. print("程序退出")
  230. return
  231. if 1 <= choice <= len(order_list):
  232. break
  233. else:
  234. print(f"请输入1-{len(order_list)}之间的数字")
  235. except ValueError:
  236. print("请输入有效的数字")
  237. except KeyboardInterrupt:
  238. print("\n程序被中断")
  239. return
  240. # 步骤4:获取选中的订单号
  241. order_no = select_order_by_index(order_list, choice)
  242. if not order_no:
  243. print("获取订单号失败")
  244. return
  245. # 步骤5:获取订单详情
  246. order_detail = get_order_detail(order_no)
  247. if not order_detail:
  248. print("获取订单详情失败")
  249. return
  250. # 步骤6:输出结果
  251. print("\n=== 解密后的订单详情 ===")
  252. print(json.dumps(order_detail, indent=2, ensure_ascii=False))
  253. # 步骤7:查找图片链接
  254. report_img = find_original_image_by_notice(order_detail, "苹果沙漏验机报告")
  255. if report_img is None:
  256. report_img = find_original_image_by_notice(order_detail, "验机照片")
  257. if report_img:
  258. print(f"\n找到验机报告图片: {report_img}")
  259. else:
  260. print("\n未找到验机报告图片")
  261. if __name__ == "__main__":
  262. main()