805 lines
31 KiB
Python
805 lines
31 KiB
Python
import os
|
||
import re
|
||
import time
|
||
import pickle
|
||
import requests
|
||
from datetime import datetime
|
||
import logging
|
||
import random
|
||
import websocket
|
||
import json
|
||
from urllib.parse import unquote
|
||
import gzip
|
||
from protobuf.douyin import *
|
||
import execjs
|
||
import string
|
||
import hashlib
|
||
import urllib.parse
|
||
from threading import Thread
|
||
|
||
|
||
session = requests.session()
|
||
|
||
|
||
def load_cookies_from_file(filename):
|
||
# 以二进制写入模式打开文件
|
||
|
||
with open(filename, "rb") as f:
|
||
return pickle.load(f)
|
||
|
||
|
||
# if os.path.isfile(f'{wjm}.pkl'):
|
||
# print(f'{wjm}.pkl文件存在')
|
||
|
||
|
||
def zhengchang_ua(i):
|
||
# return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42'
|
||
if i == 0:
|
||
first_num = random.randint(55, 62)
|
||
third_num = random.randint(0, 3200)
|
||
fourth_num = random.randint(0, 140)
|
||
os_type = [
|
||
"(Linux; Android 10; MI 9 Build/QKQ1.190825.002; wv)",
|
||
"(Linux; Android 8.1.0; PBCM30 Build/OPM1.171019.011; wv)",
|
||
"(Linux; Android 6.0; HUAWEI MLA-AL10 Build/HUAWEIMLA-AL10; wv)",
|
||
"(Linux; Android 6.0.1; OPPO A57t Build/MMB29M; wv)",
|
||
"(iPhone; CPU iPhone OS 10_3_3 like Mac OS X)",
|
||
"(Linux; U; Android 9; zh-cn; Redmi 7 Build/PKQ1.181021.001)",
|
||
"(Linux; Android 9; V1914A Build/PKQ1.181016.001; wv)",
|
||
"(Linux; U; Android 10; zh-CN; ALP-AL00 Build/HUAWEIALP-AL00)",
|
||
"(Linux; Android 10; VOG-TL00 Build/HUAWEIVOG-TL00; wv)",
|
||
"(Linux; Android 9; Nokia X7 Build/PPR1.180610.011; wv)",
|
||
"(Linux; Android 9.0; S5 Build/PKQ1.190319.001; wv)",
|
||
"(Linux; Android 10; PCT-AL10 Build/HUAWEIPCT-AL10; wv)",
|
||
"(Linux; Android 10; PCT-AL10 Build/HUAWEIPCT-AL10; wv)",
|
||
"(Linux; Android 9; Mi9 Pro 5G Build/PKQ1.190714.001; wv)",
|
||
"(iPhone; CPU iPhone OS 13_4 like Mac OS X)",
|
||
"(Linux; Android 10; OXF-AN00 Build/HUAWEIOXF-AN00; wv)",
|
||
"(Linux; U; Android 9; zh-cn; V1814A Build/PKQ1.180819.001)",
|
||
"(Linux; U; Android 7.0; zh-cn; Redmi Note 4X Build/NRD90M)",
|
||
"(Linux; Android 9; RMX1991 Build/PKQ1.190630.001; wv)",
|
||
"(Linux; Android 10; JNY-AL10 Build/HUAWEIJNY-AL10; wv)",
|
||
"(Linux; Android 10; ELE-AL00 Build/HUAWEIELE-AL00; wv)",
|
||
"(Linux; Android 9; RMX1991 Build/PKQ1.190630.001; wv)",
|
||
"(Linux; U; Android 10; zh-cn; MI 8 Build/QKQ1.190828.002)",
|
||
"(Linux; Android 10; VCE-AL00 Build/HUAWEIVCE-AL00; wv)",
|
||
"(Linux; Android 8.0.0; AUM-TL20 Build/HONORAUM-TL20; wv)",
|
||
"(Linux; Android 10; ALP-AL00 Build/HUAWEIALP-AL00; wv)",
|
||
"(Linux; U; Android 10; zh-cn; MI 8 SE Build/QKQ1.190828.002)",
|
||
"(Linux; Android 7.1.1; OPPO A83 Build/N6F26Q; wv)",
|
||
"(Linux; Android 10; VOG-AL10 Build/HUAWEIVOG-AL10; wv)",
|
||
"(iPhone; CPU iPhone OS 13_3_1 like Mac OS X)",
|
||
"(Linux; U; Android 10; zh-cn; MI 9 Build/QKQ1.190825.002)",
|
||
"(Linux; Android 9; INE-TL00 Build/HUAWEIINE-TL00; wv)",
|
||
"(Linux; Android 9; ONEPLUS A6000 Build/PKQ1.180716.001; wv)",
|
||
"(Linux; U; Android 9; zh-cn; Mi9 Pro 5G Build/PKQ1.190714.001)",
|
||
"(Linux; Android 8.1.0; OPPO R11 Plus Build/OPM1.171019.011; wv)",
|
||
"(Linux; Android 8.1.0; COR-AL00 Build/HUAWEICOR-AL00; wv)",
|
||
"(Linux; Android 7.1.2; M15 Build/N2G47H; wv)",
|
||
"(Linux; arm_64; Android 7.0; LG-H870DS)",
|
||
"(Linux; U; Android 9; zh-cn; MI CC9 Pro Build/PKQ1.190302.001)",
|
||
"(Linux; Android 10; SM-G9730 Build/QP1A.190711.020; wv)",
|
||
"(Linux; Android 7.1.2; Hisense A2T Build/N2G47H; wv)",
|
||
"(Linux; U; Android 8.1.0; zh-CN; 16th Plus Build/OPM1.171019.026)",
|
||
"(Linux; U; Android 9; zh-cn; MI 8 Lite Build/PKQ1.181007.001)",
|
||
"(Linux; Android 9; PAAM00 Build/PKQ1.190414.001; wv)",
|
||
"(iPhone; CPU iPhone OS 10_1_1 like Mac OS X)",
|
||
"(iPhone; CPU iPhone OS 11_4_1 like Mac OS X)",
|
||
"(Linux; Android 9; V1914A Build/PKQ1.181016.001; wv)",
|
||
"(Linux; Android 10; PCT-AL10 Build/HUAWEIPCT-AL10; wv)",
|
||
]
|
||
chrome_version = "Chrome/{}.0.{}.{}".format(first_num, third_num, fourth_num)
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type),
|
||
"AppleWebKit/537.36",
|
||
"(KHTML, like Gecko)",
|
||
chrome_version,
|
||
"Safari/537.36",
|
||
]
|
||
)
|
||
return ua
|
||
elif i == 1:
|
||
os_type = [
|
||
"(Windows NT 6.1; WOW64)",
|
||
"(Windows NT 6.0; WOW64)",
|
||
"(Windows NT 6.2; WOW64)",
|
||
"(Windows NT 6.3; WOW64)",
|
||
"(Windows NT 5.1; WOW64)",
|
||
"(Windows NT 5.0; WOW64)",
|
||
"(Windows NT 5.2; WOW64)",
|
||
"(Windows NT 5.3; WOW64)",
|
||
"(Windows NT 10.1; WOW64)",
|
||
"(Windows NT 10.0; WOW64)",
|
||
"(Windows NT 10.2; WOW64)",
|
||
"(Windows NT 10.3; WOW64)",
|
||
"(Windows NT 6.1; WOW64; X64)",
|
||
"(Windows NT 6.0; WOW64; X64)",
|
||
"(Windows NT 6.2; WOW64; X64)",
|
||
"(Windows NT 6.3; WOW64; X64)",
|
||
"(Windows NT 5.1; WOW64; X64)",
|
||
"(Windows NT 5.0; WOW64; X64)",
|
||
"(Windows NT 5.2; WOW64; X64)",
|
||
"(Windows NT 5.3; WOW64; X64)",
|
||
"(Windows NT 10.1; WOW64; X64)",
|
||
"(Windows NT 10.0; WOW64; X64)",
|
||
"(Windows NT 10.2; WOW64; X64)",
|
||
"(Windows NT 10.3; WOW64; X64)",
|
||
"(Windows NT 6.1)",
|
||
"(Windows NT 6.0)",
|
||
"(Windows NT 6.2)",
|
||
"(Windows NT 6.3)",
|
||
"(Windows NT 5.1)",
|
||
"(Windows NT 5.0)",
|
||
"(Windows NT 5.2)",
|
||
"(Windows NT 5.3)",
|
||
"(Windows NT 10.1)",
|
||
"(Windows NT 10.0)",
|
||
"(Windows NT 10.2)",
|
||
"(Windows NT 10.3)",
|
||
]
|
||
banben = (
|
||
str(random.randint(47, 170))
|
||
+ ".0."
|
||
+ str(random.randint(2000, 2755))
|
||
+ "."
|
||
+ str(random.randint(0, 25))
|
||
)
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type),
|
||
"AppleWebKit/537.36",
|
||
"(KHTML, like Gecko)",
|
||
"Chrome/" + banben,
|
||
"Safari/537.36",
|
||
]
|
||
)
|
||
return ua
|
||
elif i == 2:
|
||
os_type = [
|
||
"(Macintosh; U; PPC Mac OS X 10_5_8; ja-jp)",
|
||
"(Windows; U; Windows NT 6.1; cs-CZ)",
|
||
"(Windows; U; Windows NT 6.0; tr-TR)",
|
||
"(Windows; U; Windows NT 5.1; ru-RU)",
|
||
"(Windows; U; Windows NT 6.0; tr-TR)",
|
||
"(Macintosh; Intel Mac OS X 10_6_8)",
|
||
"(Windows; U; Windows NT 6.1; zh-HK)",
|
||
"(Windows; U; Windows NT 6.0; ja-JP)",
|
||
"(Windows; U; Windows NT 6.0; hu-HU)",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6; de-de)",
|
||
"(Windows; U; Windows NT 6.1; ko-KR)",
|
||
"(Macintosh; Intel Mac OS X 10_7_3)",
|
||
"(Macintosh; U; PPC Mac OS X 10_5_8; ja-jp)",
|
||
"(Windows; U; Windows NT 6.1; sv-SE)",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6; fr-ch)",
|
||
"(Windows; U; Windows NT 6.1; de-DE)",
|
||
"(Windows; U; Windows NT 6.0; de-DE)",
|
||
"(Macintosh; U; Intel Mac OS X 10_5_8; zh-cn)",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6; ja-jp)",
|
||
"(Windows; U; Windows NT 6.0; en-US)",
|
||
]
|
||
banben = (
|
||
str(random.randint(533, 534))
|
||
+ "."
|
||
+ str(random.randint(18, 21))
|
||
+ "."
|
||
+ str(random.randint(1, 27))
|
||
)
|
||
chrome_version = [
|
||
"Version/5.0.3",
|
||
"Version/5.0.4",
|
||
"Version/5.0.2",
|
||
"Version/7.0.3",
|
||
"Version/6.0 Mobile/10A5355d",
|
||
"Version/5.1.7",
|
||
"Version/5.1.6",
|
||
"Version/5.1.3",
|
||
"Version/5.1.4",
|
||
"Version/5.1.2",
|
||
"Version/5.1.3",
|
||
]
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type),
|
||
"AppleWebKit/" + banben,
|
||
"(KHTML, like Gecko)",
|
||
random.choice(chrome_version),
|
||
"Safari/" + banben,
|
||
]
|
||
)
|
||
return ua
|
||
elif i == 3:
|
||
os_type = [
|
||
"(Windows NT 10.0; Win64; x64; rv:",
|
||
"(Windows NT 6.3; Win64; x64; rv:",
|
||
"(Windows NT 6.2; Win64; x64; rv:",
|
||
"(Windows NT 10; rv:",
|
||
"(Windows NT 6.3; rv:",
|
||
"(Windows NT 6.2; rv:",
|
||
"(Windows NT 6.1; rv:",
|
||
"(Windows NT 6.1; Win64; x64; rv:",
|
||
"(X11; Linux i586; rv:",
|
||
"(Windows NT 10.0; Win64; x64; rv:",
|
||
]
|
||
banben = str(random.randint(20, 50)) + ".0"
|
||
chrome_version = [
|
||
"Gecko/20100101 Firefox/",
|
||
"Gecko/20130405 Firefox/",
|
||
"Gecko/20130330 Firefox/",
|
||
"Gecko/20130430 Firefox/",
|
||
"Gecko/20140230 Firefox/",
|
||
"Gecko/20140630 Firefox/",
|
||
"Gecko/20140512 Firefox/",
|
||
"Gecko/20140712 Firefox/",
|
||
"Gecko/20100502 Firefox/",
|
||
]
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type) + banben + ")",
|
||
random.choice(chrome_version) + banben,
|
||
]
|
||
)
|
||
return ua
|
||
elif i == 4:
|
||
os_type = [
|
||
"(Macintosh; U; Intel Mac OS X 10_6_7; ",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_5; ",
|
||
"(Windows; U; Windows NT 6.1; ",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6; ",
|
||
"(Windows; U; Windows NT 6.0; ",
|
||
"(Windows; U; Windows NT 6.1; ",
|
||
"(Windows; U; Windows NT 5.1; ",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6; ",
|
||
"(Macintosh; U; PPC Mac OS X 10_5_8;",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_7;",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_5;",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6;",
|
||
]
|
||
diqu = [
|
||
"ja-jp)",
|
||
"de-de)",
|
||
"de-DE)",
|
||
"fr-ch)",
|
||
"en-US)",
|
||
"cs-CZ)",
|
||
"it-it)",
|
||
"ko-kr)",
|
||
"da-dk)",
|
||
"ar)",
|
||
"hu-HU)",
|
||
"ko-KR)",
|
||
"es-es)",
|
||
"zh-HK)",
|
||
"en-gb)",
|
||
]
|
||
banben = (
|
||
str(random.randint(532, 535))
|
||
+ "."
|
||
+ str(random.randint(19, 55))
|
||
+ "."
|
||
+ str(random.randint(1, 25))
|
||
)
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type) + random.choice(diqu),
|
||
"AppleWebKit/" + banben,
|
||
"(KHTML, like Gecko)",
|
||
"Version/5.0." + str(random.randint(1, 5)),
|
||
"Safari/" + banben,
|
||
]
|
||
)
|
||
return ua
|
||
elif i == 5:
|
||
os_type = [
|
||
"(Windows; U; Windows NT 5.1",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6",
|
||
"(Macintosh; U; PPC Mac OS X 10_5_8",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_7",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_5",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6",
|
||
"(Macintosh; AMD Mac OS X 10_8_2",
|
||
"(Macintosh; Intel Mac OS X 10_10_1",
|
||
"(Macintosh; Intel Mac OS X 10_5_8",
|
||
"(Macintosh; Intel Mac OS X 10_6_0",
|
||
"(Macintosh; Intel Mac OS X 10_6_2",
|
||
"(Macintosh; Intel Mac OS X 10_6_3",
|
||
"(Macintosh; Intel Mac OS X 10_6_4",
|
||
"(Macintosh; Intel Mac OS X 10_6_5",
|
||
"(Macintosh; Intel Mac OS X 10_6_6",
|
||
"(Macintosh; Intel Mac OS X 10_6_7",
|
||
"(Macintosh; Intel Mac OS X 10_6_8",
|
||
"(Macintosh; Intel Mac OS X 10_7_0",
|
||
"(Macintosh; Intel Mac OS X 10_7_1",
|
||
"(Macintosh; Intel Mac OS X 10_7_2",
|
||
"(Macintosh; Intel Mac OS X 10_7_3",
|
||
"(Macintosh; Intel Mac OS X 10_7_4",
|
||
"(Macintosh; Intel Mac OS X 10_7_5",
|
||
"(Macintosh; Intel Mac OS X 10_8_0",
|
||
"(Macintosh; Intel Mac OS X 10_8_1",
|
||
"(Macintosh; Intel Mac OS X 10_8_2",
|
||
"(Macintosh; Intel Mac OS X 10_8_3",
|
||
"(Macintosh; Intel Mac OS X 10_9_0",
|
||
"(Macintosh; Intel Mac OS X 10_9_1",
|
||
"(Macintosh; Intel Mac OS X 10_9_2",
|
||
"(Macintosh; Intel Mac OS X 10_9_3",
|
||
"(Macintosh; PPC Mac OS X 10_6_7",
|
||
"(Macintosh; U; Intel Mac OS X 10_5_6",
|
||
"(Macintosh; U; Intel Mac OS X 10_5_7",
|
||
"(Macintosh; U; Intel Mac OS X 10_5_8",
|
||
"(Macintosh; U; Intel Mac OS X 10_5_9",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_0",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_1",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_2",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_3",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_4",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_5",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_6",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_7",
|
||
"(Macintosh; U; Intel Mac OS X 10_6_8",
|
||
"(Macintosh; U; Intel Mac OS X 10_8",
|
||
]
|
||
diqu = [
|
||
"; ja-jp)",
|
||
"; e-de)",
|
||
"; de-DE)",
|
||
"; fr-ch)",
|
||
"; en-US)",
|
||
"; cs-CZ)",
|
||
"; it-it)",
|
||
"; ko-kr)",
|
||
"; da-dk)",
|
||
"; ar)",
|
||
"; hu-HU)",
|
||
"; ko-KR)",
|
||
"; es-es)",
|
||
"; zh-HK)",
|
||
"; en-gb)",
|
||
"; id-ID)",
|
||
]
|
||
banben = (
|
||
str(random.randint(500, 535))
|
||
+ "."
|
||
+ str(random.randint(0, 55))
|
||
+ "."
|
||
+ str(random.randint(0, 25))
|
||
)
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type) + random.choice(diqu),
|
||
"AppleWebKit/" + banben,
|
||
"(KHTML, like Gecko)",
|
||
"Version/5.0." + str(random.randint(1, 9)),
|
||
"Safari/" + banben,
|
||
]
|
||
)
|
||
return ua
|
||
else:
|
||
os_type = [
|
||
"(iPhone; U; CPU iPhone OS 4_3_1 like Mac OS X",
|
||
"(iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X",
|
||
"(iPhone; U; CPU iPhone OS 4_3 like Mac OS X",
|
||
"(iPhone; U; CPU iPhone OS 4_2_4 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 12_1_4 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 12_0 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 11_2 like Mac OS X",
|
||
"(iPhone 6s; CPU iPhone OS 11_4_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 10_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 11_0_2 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 11_4_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 10_1_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 13_5_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 8_3 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 14_4 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 13_6 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 14_1 like Mac OS X",
|
||
"(iPhone; CPU iPhone OS 13_6_1 like Mac OS X",
|
||
]
|
||
diqu = [
|
||
"; ja-jp)",
|
||
"; e-de)",
|
||
"; de-DE)",
|
||
"; fr-ch)",
|
||
"; en-US)",
|
||
"; cs-CZ)",
|
||
"; it-it)",
|
||
"; ko-kr)",
|
||
"; da-dk)",
|
||
"; ar)",
|
||
"; hu-HU)",
|
||
"; ko-KR)",
|
||
"; es-es)",
|
||
"; zh-HK)",
|
||
"; en-gb)",
|
||
"; id-ID)",
|
||
]
|
||
banben = (
|
||
str(random.randint(500, 535))
|
||
+ "."
|
||
+ str(random.randint(0, 55))
|
||
+ "."
|
||
+ str(random.randint(0, 25))
|
||
)
|
||
|
||
mobi = [
|
||
"Version/6.0 Mobile/10A5355d",
|
||
"Version/5.1 Mobile/9B176",
|
||
"Version/5.0.2 Mobile/8J2",
|
||
"Version/5.0.2 Mobile/8G4",
|
||
"Version/5.0.2 Mobile/8C148",
|
||
"Version/5.0.2 Mobile/8C148a",
|
||
"Version/5.0.2 Mobile/8G4",
|
||
"Version/5.0.2 Mobile/8F190",
|
||
"Version/4.0.5 Mobile/8B5097d",
|
||
"Version/4.0.5 Mobile/8B117",
|
||
"Version/4.0.4 Mobile/7B314",
|
||
"Version/4.0.4 Mobile/7B334b",
|
||
"Version/4.0.4 Mobile/7D11",
|
||
"Version/4.0.4 Mobile/7B500",
|
||
"Version/4.0.4 Mobile/7B360",
|
||
"Version/3.1.1 Mobile/5G77",
|
||
]
|
||
|
||
ua = " ".join(
|
||
[
|
||
"Mozilla/5.0",
|
||
random.choice(os_type) + random.choice(diqu),
|
||
"AppleWebKit/" + banben,
|
||
"(KHTML, like Gecko)",
|
||
random.choice(mobi),
|
||
"Safari/" + banben,
|
||
]
|
||
)
|
||
return ua
|
||
|
||
|
||
def generateSignature(wss):
|
||
"""
|
||
出现gbk编码问题则修改 python模块subprocess.py的源码中Popen类的__init__函数参数encoding值为 "utf-8"
|
||
"""
|
||
params = (
|
||
"live_id,aid,version_code,webcast_sdk_version,"
|
||
"room_id,sub_room_id,sub_channel_id,did_rule,"
|
||
"user_unique_id,device_platform,device_type,ac,"
|
||
"identity"
|
||
).split(",")
|
||
wss_params = urllib.parse.urlparse(wss).query.split("&")
|
||
wss_maps = {i.split("=")[0]: i.split("=")[-1] for i in wss_params}
|
||
tpl_params = [f"{i}={wss_maps.get(i, '')}" for i in params]
|
||
param = ",".join(tpl_params)
|
||
md5 = hashlib.md5()
|
||
md5.update(param.encode())
|
||
md5_param = md5.hexdigest()
|
||
|
||
# with codecs.open('D:\job_demo\demo\day04\h_sign.js', 'r', encoding='utf8') as f:
|
||
# script = f.read()
|
||
|
||
# ctx = MiniRacer()
|
||
# ctx.eval(script)
|
||
|
||
with open("D:\job_demo\demo\day04\h_sign.js", "r", encoding="utf-8") as f:
|
||
js_code = f.read()
|
||
ctx = execjs.compile(js_code)
|
||
|
||
try:
|
||
signature = ctx.call("get_sign", md5_param)
|
||
return signature
|
||
except Exception as e:
|
||
print(e)
|
||
|
||
|
||
def generateMsToken(length=107):
|
||
"""
|
||
产生请求头部cookie中的msToken字段,其实为随机的107位字符
|
||
:param length:字符位数
|
||
:return:msToken
|
||
"""
|
||
random_str = ""
|
||
base_str = string.ascii_letters + string.digits + "=_"
|
||
_len = len(base_str) - 1
|
||
for _ in range(length):
|
||
random_str += base_str[random.randint(0, _len)]
|
||
return random_str
|
||
|
||
|
||
class DouyinLiveWebFetcher:
|
||
def __init__(self, live_url, roomId, Cookie):
|
||
self.id_dict = {}
|
||
self.Cookies = Cookie
|
||
self.__ttwid = None
|
||
self.room_id = roomId
|
||
self.live_url = live_url
|
||
self.user_agent = zhengchang_ua(1)
|
||
|
||
def start(self):
|
||
self._connectWebSocket()
|
||
|
||
def _connectWebSocket(self):
|
||
"""
|
||
连接抖音直播间websocket服务器,请求直播间数据
|
||
"""
|
||
wss = (
|
||
"wss://webcast5-ws-web-hl.douyin.com/webcast/im/push/v2/?app_name=douyin_web"
|
||
"&version_code=180800&webcast_sdk_version=1.0.14-beta.0"
|
||
"&update_version_code=1.0.14-beta.0&compress=gzip&device_platform=web&cookie_enabled=true"
|
||
"&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32"
|
||
"&browser_name=Mozilla"
|
||
"&browser_version=5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,"
|
||
"%20like%20Gecko)%20Chrome/126.0.0.0%20Safari/537.36"
|
||
"&browser_online=true&tz_name=Asia/Shanghai"
|
||
"&cursor=d-1_u-1_fh-7392091211001140287_t-1721106114633_r-1"
|
||
f"&internal_ext=internal_src:dim|wss_push_room_id:{self.room_id}|wss_push_did:7319483754668557238"
|
||
f"|first_req_ms:1721106114541|fetch_time:1721106114633|seq:1|wss_info:0-1721106114633-0-0|"
|
||
f"wrds_v:7392094459690748497"
|
||
f"&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&endpoint=live_pc&support_wrds=1"
|
||
f"&user_unique_id=7319483754668557238&im_path=/webcast/im/fetch/&identity=audience"
|
||
f"&need_persist_msg_count=15&insert_task_id=&live_reason=&room_id={self.room_id}&heartbeatDuration=0"
|
||
)
|
||
|
||
signature = generateSignature(wss)
|
||
wss += f"&signature={signature}"
|
||
|
||
headers = {
|
||
"cookie": f"ttwid={self.ttwid}",
|
||
"user-agent": self.user_agent,
|
||
}
|
||
self.ws = websocket.WebSocketApp(
|
||
wss,
|
||
header=headers,
|
||
on_open=self._wsOnOpen,
|
||
on_message=self._wsOnMessage,
|
||
on_error=self._wsOnError,
|
||
on_close=self._wsOnClose,
|
||
)
|
||
# 运行websocket连接,并处理可能的异常
|
||
try:
|
||
self.ws.run_forever()
|
||
except websocket.WebSocketConnectionClosedException as e:
|
||
logging.error("_connectWebSocket--WebSocket连接已关闭: %s", e)
|
||
self.stop()
|
||
except websocket.WebSocketException as e:
|
||
logging.error("_connectWebSocket--WebSocket异常: %s", e)
|
||
self.stop()
|
||
except Exception as e:
|
||
logging.error("_connectWebSocket--发生未知异常: %s", e)
|
||
self.stop()
|
||
raise # 重新抛出异常,以便上层处理
|
||
|
||
def _wsOnOpen(self, ws):
|
||
"""
|
||
连接建立成功
|
||
"""
|
||
logging.info(
|
||
f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}----直播间链接成功"
|
||
)
|
||
|
||
def heartbeat(ws: websocket.WebSocketApp):
|
||
"""发送心跳消息的定时任务"""
|
||
while True:
|
||
if ws.keep_running: # 检查WebSocket连接是否仍在运行
|
||
ws.send("hi") # 发送自定义的心跳消息
|
||
time.sleep(15) # 等待指定的时间间隔
|
||
else:
|
||
break
|
||
|
||
heartbeat_thread = Thread(target=heartbeat, args=(ws,))
|
||
heartbeat_thread.daemon = True # 设置为守护线程
|
||
heartbeat_thread.start()
|
||
|
||
def _wsOnMessage(self, ws: websocket.WebSocketApp, message: str):
|
||
"""
|
||
接收到数据
|
||
:param ws: websocket实例
|
||
:param message: 数据
|
||
"""
|
||
# while True:
|
||
# 根据proto结构体解析对象
|
||
|
||
if message:
|
||
try:
|
||
package = PushFrame().parse(message)
|
||
response = Response().parse(gzip.decompress(package.payload))
|
||
|
||
# 返回直播间服务器链接存活确认消息,便于持续获取数据
|
||
if response.need_ack:
|
||
ack = PushFrame(
|
||
log_id=package.log_id,
|
||
payload_type="ack",
|
||
payload=response.internal_ext.encode("utf-8"),
|
||
).SerializeToString()
|
||
ws.send(ack, websocket.ABNF.OPCODE_BINARY)
|
||
|
||
# 根据消息类别解析消息体
|
||
for msg in response.messages_list:
|
||
method = msg.method
|
||
try:
|
||
{
|
||
"WebcastChatMessage": self._parseChatMsg, # 聊天消息
|
||
"WebcastGiftMessage": self._parseGiftMsg, # 礼物消息
|
||
"WebcastLikeMessage": self._parseLikeMsg, # 点赞消息
|
||
"WebcastMemberMessage": self._parseMemberMsg, # 进入直播间消息
|
||
"WebcastSocialMessage": self._parseSocialMsg, # 关注消息
|
||
"WebcastRoomUserSeqMessage": self._parseRoomUserSeqMsg, # 直播间统计
|
||
"WebcastFansclubMessage": self._parseFansclubMsg, # 粉丝团消息
|
||
"WebcastControlMessage": self._parseControlMsg, # 直播间状态消息
|
||
"WebcastEmojiChatMessage": self._parseEmojiChatMsg, # 聊天表情包消息
|
||
"WebcastRoomStatsMessage": self._parseRoomStatsMsg, # 直播间统计信息
|
||
"WebcastRoomMessage": self._parseRoomMsg, # 直播间信息
|
||
"WebcastRoomRankMessage": self._parseRankMsg, # 直播间排行榜信息
|
||
}.get(method)(msg.payload)
|
||
except Exception as e:
|
||
pass
|
||
# logging.error(f"_wsOnMessage--error occurred: {e}")
|
||
|
||
except Exception as e:
|
||
logging.error(f"_wsOnMessage--error occurred: {e}")
|
||
|
||
def _wsOnError(self, ws, error):
|
||
# print("WebSocket error: ", error)
|
||
logging.info("WebSocket error: ", error)
|
||
|
||
def _wsOnClose(self, ws: websocket.WebSocketApp, *args):
|
||
logging.info(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}----直播间断开")
|
||
|
||
def _parseChatMsg(self, payload):
|
||
"""聊天消息"""
|
||
message = ChatMessage().parse(payload)
|
||
user_name = message.user.nick_name # 用户名称
|
||
user_id = message.user.id # 用户id
|
||
user_sid = message.user.sec_uid # 用户主页uid
|
||
display_id = message.user.display_id # 用户抖音ID
|
||
content = message.content # 用户发送的信息
|
||
print(
|
||
f"聊天【msg】- 用户名称:{user_name} - 用户id:{user_id} - 用户主页uid:{user_sid} - 用户抖音ID:{display_id}-用户发送的信息:{content}"
|
||
)
|
||
|
||
def _parseGiftMsg(self, payload):
|
||
"""礼物消息"""
|
||
message = GiftMessage().parse(payload)
|
||
user_name = message.user.nick_name # 用户名称
|
||
gift_name = message.gift.name # 礼物信息
|
||
gift_cnt = message.combo_count # 礼物数量
|
||
print(f"【礼物msg】-{user_name} - 送出了 {gift_name}x{gift_cnt}")
|
||
|
||
def _parseLikeMsg(self, payload):
|
||
"""点赞消息"""
|
||
message = LikeMessage().parse(payload)
|
||
user_name = message.user.nick_name # 用户名称
|
||
count = message.count # 点赞次数
|
||
print(f"【点赞msg】- {user_name} - 点了{count}个赞")
|
||
|
||
def _parseMemberMsg(self, payload):
|
||
"""进入直播间信息"""
|
||
message = MemberMessage().parse(payload)
|
||
following_coun = message.user.follow_info.following_count # 用户关注数
|
||
follower_count = message.user.follow_info.follower_count # 用户粉丝数
|
||
user_name = message.user.nick_name # 用户名称
|
||
user_sid = message.user.sec_uid # 用户主页uid
|
||
user_id = message.user.id # 用户id
|
||
display_id = message.user.display_id # 用户抖音ID
|
||
gender = ['未知',"男", "女"][message.user.gender] # 用户性别
|
||
print(
|
||
f"【进场msg】- 用户名称:{user_name} - 用户id:{user_id} - 用户uid:{user_sid} - 性别:{gender} 进入了直播间"
|
||
)
|
||
|
||
def _parseSocialMsg(self, payload):
|
||
"""关注消息"""
|
||
message = SocialMessage().parse(payload)
|
||
user_name = message.user.nick_name # 用户名称
|
||
user_sid = message.user.sec_uid # 用户主页uid
|
||
user_id = message.user.id # 用户id
|
||
display_id = message.user.display_id # 用户抖音ID
|
||
# 分享
|
||
if message.follow_count == 0:
|
||
print(f"【分享msg】- 用户名称:{user_name} - 用户id:{user_id} 分享了主播")
|
||
# 关注
|
||
else:
|
||
print(f"【分享msg】- 用户名称:{user_name} - 用户id:{user_id} 关注了主播")
|
||
|
||
def _parseRoomUserSeqMsg(self, payload):
|
||
"""直播间统计"""
|
||
message = RoomUserSeqMessage().parse(payload)
|
||
current = message.total # 当前观看人数
|
||
total = message.total_pv_for_anchor # 累计观看人数
|
||
print(f"【统计msg】- 当前观看人数: {current} - 累计观看人数: {total}")
|
||
|
||
def _parseFansclubMsg(self, payload):
|
||
"""粉丝团消息"""
|
||
message = FansclubMessage().parse(payload)
|
||
content = message.content # 内容
|
||
print(f"【粉丝团msg】 {content}")
|
||
|
||
def _parseControlMsg(self, payload):
|
||
"""直播间状态消息"""
|
||
message = ControlMessage().parse(payload)
|
||
|
||
if message.status == 3:
|
||
print("直播间已结束")
|
||
print(f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}----直播间已结束')
|
||
self.stop()
|
||
|
||
def _parseEmojiChatMsg(self, payload):
|
||
"""聊天表情包消息"""
|
||
message = EmojiChatMessage().parse(payload)
|
||
emoji_id = message.emoji_id # 表情包id
|
||
user = message.user # 用户
|
||
common = message.common # 通用信息
|
||
default_content = message.default_content # 默认内容
|
||
print(
|
||
f"【聊天表情包id】- {emoji_id} - user:{user} - common:{common} - default_content:{default_content}"
|
||
)
|
||
|
||
def _parseRoomStatsMsg(self, payload):
|
||
"""直播间统计msg"""
|
||
message = RoomStatsMessage().parse(payload)
|
||
display_long = message.display_long # 直播间统计信息
|
||
print(f"【直播间统计msg】- {display_long}")
|
||
|
||
def _parseRoomMsg(self, payload):
|
||
"""直播间msg"""
|
||
message = RoomMessage().parse(payload)
|
||
common = message.common
|
||
room_id = common.room_id # 直播间id
|
||
print(f"【直播间msg】- 直播间id:{room_id}")
|
||
|
||
def _parseRankMsg(self, payload):
|
||
"""直播间排行榜msg"""
|
||
message = RoomRankMessage().parse(payload)
|
||
ranks_list = message.ranks_list
|
||
print(f"【直播间排行榜msg】{ranks_list}")
|
||
|
||
@property
|
||
def ttwid(self):
|
||
"""
|
||
产生请求头部cookie中的ttwid字段,访问抖音网页版直播间首页可以获取到响应cookie中的ttwid
|
||
:return: ttwid
|
||
"""
|
||
if self.__ttwid:
|
||
return self.__ttwid
|
||
headers = {
|
||
"User-Agent": self.user_agent,
|
||
}
|
||
try:
|
||
response = requests.get(
|
||
"https://live.douyin.com/", headers=headers, verify=False
|
||
)
|
||
response.raise_for_status()
|
||
except Exception as e:
|
||
logging.error(f"ttwid--error occurred: {e}")
|
||
|
||
else:
|
||
self.__ttwid = response.cookies.get("ttwid")
|
||
return self.__ttwid
|
||
|
||
|
||
if __name__ == "__main__":
|
||
user_name = ""
|
||
with open(r"D:\job_demo\demo\测试\cookie_name.txt", "r", encoding="utf-8") as f:
|
||
|
||
user_name = f.read().split("|")[1].strip()
|
||
Cookie = load_cookies_from_file(
|
||
r"D:\job_demo\demo\测试\MS4wLjABAAAAc9m4vmspNsSiYP348XRC-OLVqSXRn8Rdtl618fbzYag.pkl"
|
||
)
|
||
# print(Cookie)
|
||
# print(type(Cookie))
|
||
cookies_dict = {c.name: c.value for c in Cookie}
|
||
cookie_str = "; ".join(f"{k}={v}" for k, v in cookies_dict.items())
|
||
|
||
|
||
|
||
live_url = 'https://live.douyin.com/80017709309'
|
||
roomId = '7502218243671739173'
|
||
DouyinLiveWebFetcher(live_url,roomId,cookie_str).start()
|
||
|
||
|