douyin_author_help.py 4.3 KB

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