help.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. import base64
  2. import ctypes
  3. import json
  4. import math
  5. import random
  6. import time
  7. import urllib.parse
  8. from Crypto.Cipher import DES
  9. from matplotlib import pyplot as plt
  10. def sign(a1="", b1="", x_s="", x_t=""):
  11. """
  12. takes in a URI (uniform resource identifier), an optional data dictionary, and an optional ctime parameter. It returns a dictionary containing two keys: "x-s" and "x-t".
  13. """
  14. common = {
  15. "s0": 3, # getPlatformCode
  16. "s1": "",
  17. "x0": "1", # localStorage.getItem("b1b1")
  18. "x1": "3.7.8-2", # version
  19. "x2": "Mac OS",
  20. "x3": "xhs-pc-web",
  21. "x4": "4.27.2",
  22. "x5": a1, # cookie of a1
  23. "x6": x_t,
  24. "x7": x_s,
  25. "x8": b1, # localStorage.getItem("b1")
  26. "x9": mrc(x_t + x_s + b1),
  27. "x10": 154, # getSigCount
  28. }
  29. encode_str = encodeUtf8(json.dumps(common, separators=(',', ':')))
  30. x_s_common = b64Encode(encode_str)
  31. x_b3_traceid = get_b3_trace_id()
  32. return {
  33. "x-s": x_s,
  34. "x-t": x_t,
  35. "x-s-common": x_s_common,
  36. "x-b3-traceid": x_b3_traceid
  37. }
  38. def get_b3_trace_id():
  39. re = "abcdef0123456789"
  40. je = 16
  41. e = ""
  42. for t in range(16):
  43. e += re[random.randint(0, je - 1)]
  44. return e
  45. def mrc(e):
  46. ie = [
  47. 0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685,
  48. 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995,
  49. 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648,
  50. 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990,
  51. 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755,
  52. 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145,
  53. 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206,
  54. 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980,
  55. 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705,
  56. 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527,
  57. 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772,
  58. 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290,
  59. 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719,
  60. 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925,
  61. 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202,
  62. 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960,
  63. 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733,
  64. 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467,
  65. 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048,
  66. 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054,
  67. 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443,
  68. 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945,
  69. 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430,
  70. 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580,
  71. 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225,
  72. 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143,
  73. 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732,
  74. 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850,
  75. 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135,
  76. 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109,
  77. 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954,
  78. 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920,
  79. 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877,
  80. 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603,
  81. 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992,
  82. 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934,
  83. 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795,
  84. 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105,
  85. 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270,
  86. 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108,
  87. 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449,
  88. 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471,
  89. 3272380065, 1510334235, 755167117,
  90. ]
  91. o = -1
  92. def right_without_sign(num: int, bit: int=0) -> int:
  93. val = ctypes.c_uint32(num).value >> bit
  94. MAX32INT = 4294967295
  95. return (val + (MAX32INT + 1)) % (2 * (MAX32INT + 1)) - MAX32INT - 1
  96. for n in range(57):
  97. o = ie[(o & 255) ^ ord(e[n])] ^ right_without_sign(o, 8)
  98. return o ^ -1 ^ 3988292384
  99. lookup = [
  100. "Z",
  101. "m",
  102. "s",
  103. "e",
  104. "r",
  105. "b",
  106. "B",
  107. "o",
  108. "H",
  109. "Q",
  110. "t",
  111. "N",
  112. "P",
  113. "+",
  114. "w",
  115. "O",
  116. "c",
  117. "z",
  118. "a",
  119. "/",
  120. "L",
  121. "p",
  122. "n",
  123. "g",
  124. "G",
  125. "8",
  126. "y",
  127. "J",
  128. "q",
  129. "4",
  130. "2",
  131. "K",
  132. "W",
  133. "Y",
  134. "j",
  135. "0",
  136. "D",
  137. "S",
  138. "f",
  139. "d",
  140. "i",
  141. "k",
  142. "x",
  143. "3",
  144. "V",
  145. "T",
  146. "1",
  147. "6",
  148. "I",
  149. "l",
  150. "U",
  151. "A",
  152. "F",
  153. "M",
  154. "9",
  155. "7",
  156. "h",
  157. "E",
  158. "C",
  159. "v",
  160. "u",
  161. "R",
  162. "X",
  163. "5",
  164. ]
  165. def tripletToBase64(e):
  166. return (
  167. lookup[63 & (e >> 18)] +
  168. lookup[63 & (e >> 12)] +
  169. lookup[(e >> 6) & 63] +
  170. lookup[e & 63]
  171. )
  172. def encodeChunk(e, t, r):
  173. m = []
  174. for b in range(t, r, 3):
  175. n = (16711680 & (e[b] << 16)) + \
  176. ((e[b + 1] << 8) & 65280) + (e[b + 2] & 255)
  177. m.append(tripletToBase64(n))
  178. return ''.join(m)
  179. def b64Encode(e):
  180. P = len(e)
  181. W = P % 3
  182. U = []
  183. z = 16383
  184. H = 0
  185. Z = P - W
  186. while H < Z:
  187. U.append(encodeChunk(e, H, Z if H + z > Z else H + z))
  188. H += z
  189. if 1 == W:
  190. F = e[P - 1]
  191. U.append(lookup[F >> 2] + lookup[(F << 4) & 63] + "==")
  192. elif 2 == W:
  193. F = (e[P - 2] << 8) + e[P - 1]
  194. U.append(lookup[F >> 10] + lookup[63 & (F >> 4)] +
  195. lookup[(F << 2) & 63] + "=")
  196. return "".join(U)
  197. def encodeUtf8(e):
  198. b = []
  199. m = urllib.parse.quote(e, safe='~()*!.\'')
  200. w = 0
  201. while w < len(m):
  202. T = m[w]
  203. if T == "%":
  204. E = m[w + 1] + m[w + 2]
  205. S = int(E, 16)
  206. b.append(S)
  207. w += 2
  208. else:
  209. b.append(ord(T[0]))
  210. w += 1
  211. return b
  212. def base36encode(number, alphabet='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
  213. """Converts an integer to a base36 string."""
  214. if not isinstance(number, int):
  215. raise TypeError('number must be an integer')
  216. base36 = ''
  217. sign = ''
  218. if number < 0:
  219. sign = '-'
  220. number = -number
  221. if 0 <= number < len(alphabet):
  222. return sign + alphabet[number]
  223. while number != 0:
  224. number, i = divmod(number, len(alphabet))
  225. base36 = alphabet[i] + base36
  226. return sign + base36
  227. def base36decode(number):
  228. return int(number, 36)
  229. def get_search_id():
  230. e = int(time.time() * 1000) << 64
  231. t = int(random.uniform(0, 2147483646))
  232. return base36encode((e + t))
  233. img_cdns = [
  234. "https://sns-img-qc.xhscdn.com",
  235. "https://sns-img-hw.xhscdn.com",
  236. "https://sns-img-bd.xhscdn.com",
  237. "https://sns-img-qn.xhscdn.com",
  238. ]
  239. def get_img_url_by_trace_id(trace_id: str, format_type: str = "png"):
  240. return f"{random.choice(img_cdns)}/{trace_id}?imageView2/format/{format_type}"
  241. def get_img_urls_by_trace_id(trace_id: str, format_type: str = "png"):
  242. return [f"{cdn}/{trace_id}?imageView2/format/{format_type}" for cdn in img_cdns]
  243. def get_trace_id(img_url: str):
  244. # 浏览器端上传的图片多了 /spectrum/ 这个路径
  245. return f"spectrum/{img_url.split('/')[-1]}" if img_url.find("spectrum") != -1 else img_url.split("/")[-1]
  246. BS = DES.block_size
  247. class Des:
  248. key_map = {"mouseEnd": 'WquqhEkd', "track": 'PYrm8rMk', "time": 'vPMvCY4K', "captchaInfo": '76a2171c'}
  249. @staticmethod
  250. def pad(s):
  251. return s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
  252. @staticmethod
  253. def unpad(s):
  254. return s[0:-ord(s[-1])]
  255. def encrypt(self, key, text):
  256. text = self.pad(text)
  257. cryptor = DES.new(self.key_map[key].encode(), DES.MODE_ECB)
  258. x = len(text) % 8
  259. if x != 0:
  260. text = text + '\0' * (8 - x)
  261. ciphertext = cryptor.encrypt(text.encode())
  262. return base64.standard_b64encode(ciphertext).decode("utf-8")
  263. def decrypt(self, key, text):
  264. cryptor = DES.new(self.key_map[key].encode(), DES.MODE_ECB)
  265. de_text = base64.standard_b64decode(text)
  266. plain_text = cryptor.decrypt(de_text)
  267. st = str(plain_text.decode("utf-8")).rstrip('\0')
  268. out = self.unpad(st)
  269. return out
  270. class GenerateCurve:
  271. '''根据两点坐标确定一条被瑟尔曲线'''
  272. def __init__(self, point0, point1, control_point=[], point_nums=random.randint(0, 3), debug=False):
  273. '''
  274. :param point0: 起点
  275. :param point1: 终点
  276. :param control_point: 控制点
  277. :param point_nums: 生成曲线坐标点的数量.数量越多图越凹凸不平,越少越平滑
  278. '''
  279. self.point0 = point0
  280. self.point1 = point1
  281. self.control_point = control_point
  282. self.point_nums = point_nums
  283. self.debug = debug
  284. def getBezierPoints(self):
  285. '''
  286. :return:
  287. '''
  288. if not self.point_nums:
  289. self.point_nums = random.randint(1, 6)
  290. pointList = []
  291. x1, y1 = int(self.point0[0]), int(self.point0[1])
  292. x2, y2 = int(self.point1[0]), int(self.point1[1])
  293. cx, cy = int(self.control_point[0]), int(self.control_point[1])
  294. tm = 0
  295. for i in range(self.point_nums + 1):
  296. t = i / self.point_nums
  297. x = math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * cx + math.pow(t, 2) * x2
  298. y = math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * cy + math.pow(t, 2) * y2
  299. tm += random.randint(15, 30)
  300. pointList.append([int(x), int(y), int(tm)])
  301. return pointList
  302. def getControlPoint(self):
  303. '''
  304. :return: 控制点
  305. '''
  306. if self.control_point:
  307. return self.control_point
  308. x0, y0 = int(self.point0[0]), int(self.point0[1])
  309. x1, y1 = int(self.point1[0]), int(self.point1[1])
  310. abs_x = abs(x0 - x1) / 2 # 两点横坐标相减绝对值/2
  311. abs_y = abs(y0 - y1) / 2 # 两点横坐标相减绝对值/2
  312. # print(abs_y)
  313. ran_x = random.randint(0, int(abs_x)) # x取随机差值
  314. ran_y = random.randint(0, int(abs_y)) # y取随机差值
  315. # print(ran_x, ran_y)
  316. self.control_point.append((x0 + x1) / 2 + random.choice([-ran_x, +ran_x]))
  317. self.control_point.append((y0 + y1) / 2 + random.choice([-ran_y, +ran_y]))
  318. def showRoute(self, pointList):
  319. '''
  320. 展示曲线走势
  321. :return:
  322. '''
  323. pass
  324. _xx = []
  325. _yy = []
  326. for p in pointList:
  327. _xx.append(p[0])
  328. _yy.append(p[1])
  329. plt.plot(_xx, _yy, 'b-')
  330. plt.show()
  331. def main(self):
  332. self.getControlPoint()
  333. pointList = self.getBezierPoints()
  334. if self.debug == True:
  335. self.showRoute(pointList)
  336. return pointList
  337. if __name__ == '__main__':
  338. _img_url = "https://sns-img-bd.xhscdn.com/7a3abfaf-90c1-a828-5de7-022c80b92aa3"
  339. # 获取一个图片地址在多个cdn下的url地址
  340. # final_img_urls = get_img_urls_by_trace_id(get_trace_id(_img_url))
  341. final_img_url = get_img_url_by_trace_id(get_trace_id(_img_url))
  342. print(final_img_url)