douyin_author_scheduling_help.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import json
  2. import time
  3. from base64 import b64encode
  4. from functools import reduce
  5. from hashlib import md5
  6. from random import choice, randint
  7. from typing import Any, Dict, List, Optional
  8. from urllib.parse import urlencode
  9. class DouYinHelper(object):
  10. ttwid_list = [
  11. '1|G3wy_-RdLJnfG5P9zAcP54OM8_nTLZVrJxNi1lPzdmg|1693558867|5e43c47a424e939aaf7193b096e3c6f2274982ee64e9608c99c54d2a43982aca'
  12. ]
  13. @classmethod
  14. def _0x30492c(cls, x: bytes, y: bytes, f: Optional[List[int]] = None) -> bytes:
  15. """RC4加密, 可以用Crypto.Cipher.ARC4替代"""
  16. c = 0
  17. d = [i for i in range(256)]
  18. for b in range(256):
  19. c = (c + d[b] + x[b % len(x)]) % 256
  20. e = d[b]
  21. d[b] = d[c]
  22. d[c] = e
  23. t, c = 0, 0
  24. if not f:
  25. f = []
  26. for i in range(len(y)):
  27. t = (t + 1) % 256
  28. c = (c + d[t]) % 256
  29. e = d[t]
  30. d[t] = d[c]
  31. d[c] = e
  32. f.append(y[i] ^ d[(d[t] + d[c]) % 256])
  33. return bytes(f)
  34. @classmethod
  35. def _0x485470(cls, a: str) -> List[int]:
  36. _0x583e81 = [0] * 103
  37. for i in range(10):
  38. _0x583e81[i + 48] = i
  39. for j in range(10, 16):
  40. _0x583e81[j + 87] = j
  41. b = len(a) >> 1
  42. e = b << 1
  43. d = [0] * b
  44. c = 0
  45. for f in range(0, e, 2):
  46. d[c] = _0x583e81[ord(a[f])] << 4 | _0x583e81[ord(a[f + 1])]
  47. c += 1
  48. return d
  49. @classmethod
  50. def calc_x_bogus(cls, ua: str, query: str, data: Optional[Dict[str, Any]] = None) -> str:
  51. """计算X_Bogus参数"""
  52. query = query.encode()
  53. for _ in range(2):
  54. query = md5(query).hexdigest()
  55. query = bytes([int(query[i:i + 2], 16) for i in range(0, len(query), 2)])
  56. data = json.dumps(data, separators=(',', ':'), ensure_ascii=False).encode() if data else b''
  57. for _ in range(2):
  58. data = md5(data).hexdigest()
  59. data = bytes([int(data[i:i + 2], 16) for i in range(0, len(data), 2)])
  60. a = b'\x00\x01\x0e'
  61. ua = b64encode(cls._0x30492c(a, ua.encode())).decode()
  62. ua = md5(ua.encode()).hexdigest()
  63. ua = cls._0x485470(ua)
  64. t = int(time.time())
  65. fp = 2421646185 # 真实的canvas指纹
  66. arr1 = [
  67. 64,
  68. 1 / 256,
  69. 1 % 256,
  70. 14,
  71. query[14],
  72. query[15],
  73. data[14],
  74. data[15],
  75. ua[14],
  76. ua[15],
  77. t >> 24 & 255,
  78. t >> 16 & 255,
  79. t >> 8 & 255,
  80. t >> 0 & 255,
  81. fp >> 24 & 255,
  82. fp >> 16 & 255,
  83. fp >> 8 & 255,
  84. fp >> 0 & 255,
  85. ]
  86. reduce_num = reduce(lambda x, y: int(x) ^ int(y), arr1)
  87. arr1.append(reduce_num)
  88. arr2 = [int(arr1[i]) for i in range(len(arr1))]
  89. garble = cls._0x30492c(b'\xff', bytes(arr2), [2, 255])
  90. m = 'Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe='
  91. xb = ''
  92. for i in range(0, len(garble), 3):
  93. a, b, c = garble[i], garble[i + 1], garble[i + 2]
  94. base_num = c | b << 8 | a << 16
  95. c1 = m[(base_num & 16515072) >> 18]
  96. c2 = m[(base_num & 258048) >> 12]
  97. c3 = m[(base_num & 4032) >> 6]
  98. c4 = m[(base_num & 63)]
  99. xb += ''.join([c1, c2, c3, c4])
  100. return xb
  101. @classmethod
  102. def get_full_query(cls, ua: str, extra_data: Dict[str, Any]) -> Dict[str, Any]:
  103. ms_token = b64encode(bytes([randint(0, 255) for _ in range(94)])).decode()
  104. ms_token = ms_token.replace('+', '-').replace('/', '_').rstrip('=')
  105. data = {
  106. 'device_platform': 'webapp',
  107. 'aid': '6383',
  108. 'channel': 'channel_pc_web',
  109. 'pc_client_type': '1',
  110. 'version_code': '190500',
  111. 'version_name': '19.5.0',
  112. 'cookie_enabled': 'true',
  113. 'platform': 'PC',
  114. 'msToken': ms_token,
  115. }
  116. data.update(extra_data)
  117. query = urlencode(data, safe='=')
  118. x_bogus = cls.calc_x_bogus(ua=ua, query=query, data=None)
  119. data.update({'X-Bogus': x_bogus})
  120. return data
  121. @classmethod
  122. def get_cookie(cls):
  123. ttwid = choice(cls.ttwid_list)
  124. return f'ttwid={ttwid}'