diff --git a/README.md b/README.md index d64f93a..443076d 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,15 @@ - 运行主文件main.py启动程序 - 在config文件夹内的配置文件中对录制进行配置以及添加录制直播间地址 - 录制需要使用到PC端直播间页面的Cookie,请先在config.ini配置文件中添加后再进行录制 -- 注意事项① 录制使用到了ffmpeg,如果没有则无法进行录制 +- 注意事项① 录制使用到了ffmpeg,如果没有则无法进行录制,请将ffmpeg.exe放置运行文件同个文件夹 - 注意事项② 录制Tiktok时需要使用vpn代理,请先在配置文件中设置开启代理并添加proxy_addr - 注意事项③ 如果电脑开启了全局或者规则代理,可不用添加proxy_addr参数值但仍需在config.ini配置文件中设置开启代理 -- 抖音app端直播间分享地址和网页端长地址都能正常进行录制(尽量用长链接,避免因短链接转换失效导致不能正常录制),Tiktok直播间地址目前只支持一种 +- 注意事项④,不知道是不是ffmpeg的原因,测试时在Pycharm中运行进行直播录制,录制出来的视频无法正常播放,而在命令控制台DOS界面运行代码,录制出来的视频可正常播放,这点请注意,别误认为不能录制。   +抖音app端直播间分享地址和网页端长地址都能正常进行录制(尽量用长链接,避免因短链接转换失效导致不能正常录制),Tiktok和快手直播间地址目前只支持一种。 + 抖音直播间链接示例: ``` @@ -55,16 +57,25 @@ https://www.tiktok.com/@bougiebulliesandbirds/live 请求示例:https://hmily.vip/api/dy/live/?url=https://live.douyin.com/573716250978 -(只支持抖音,Tiktok的没写) +短地址转换长地址:https://hmily.vip/api/dy/live/convert?url=https://v.douyin.com/iQLgKSj/ + +注:本测试API只写了抖音的 + +  + +## ❤️贡献者 + +   [![Hmily](https://github.com/ihmily.png?size=50)](https://github.com/ihmily)   ## 提交日志 -  +- 20230804 + - 新增了快手直播录制,优化了部分代码 - 20230803 - - 通宵更新 一直熬夜一直爽 + - 通宵更新 - 新增了国际版抖音Tiktok的直播录制,去除冗余 简化了部分代码 - 20230724 @@ -73,6 +84,6 @@ https://www.tiktok.com/@bougiebulliesandbirds/live   -## 有问题可以提issue 或 参与pr,后续我会在这里不断更新其他直播平台的录制 欢迎给个star +## 有问题可以提issue 或 参与pr,后续我会在这里不断更新其他直播平台的录制 欢迎给个Star #### diff --git a/config/URL_config.ini b/config/URL_config.ini index 2c3cc9b..45e283f 100644 --- a/config/URL_config.ini +++ b/config/URL_config.ini @@ -1,3 +1,2 @@ https://live.douyin.com/326500301367 -https://live.douyin.com/466747346712 -https://live.douyin.com/973349577278 \ No newline at end of file +https://live.kuaishou.com/u/yall1102 \ No newline at end of file diff --git a/config/config.ini b/config/config.ini index 8027165..ba27257 100644 --- a/config/config.ini +++ b/config/config.ini @@ -15,7 +15,5 @@ ts录制完成后自动增加生成mp4格式 = 否 ts录制完成后自动增加生成m4a格式 = 否 追加格式后删除原文件 = 否 生成时间文件 = 否 -是否显示浏览器 = 否 -仅用浏览器录制 = 否 cookies(不可为空) = ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511; my_rd=1; passport_csrf_token=3ab34460fa656183fccfb904b16ff742; passport_csrf_token_default=3ab34460fa656183fccfb904b16ff742; d_ticket=9f562383ac0547d0b561904513229d76c9c21; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; store-region=cn-fj; store-region-src=uid; LOGIN_STATUS=1; __security_server_data_status=1; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; pwa2=%223%7C0%7C3%7C0%22; download_guide=%223%2F20230729%2F0%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.6%7D; strategyABtestKey=%221690824679.923%22; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; VIDEO_FILTER_MEMO_SELECT=%7B%22expireTime%22%3A1691443863751%2C%22type%22%3Anull%7D; home_can_add_dy_2_desktop=%221%22; __live_version__=%221.1.1.2169%22; device_web_cpu_core=8; device_web_memory_size=8; xgplayer_user_id=346045893336; csrf_session_id=2e00356b5cd8544d17a0e66484946f28; odin_tt=724eb4dd23bc6ffaed9a1571ac4c757ef597768a70c75fef695b95845b7ffcd8b1524278c2ac31c2587996d058e03414595f0a4e856c53bd0d5e5f56dc6d82e24004dc77773e6b83ced6f80f1bb70627; __ac_nonce=064caded4009deafd8b89; __ac_signature=_02B4Z6wo00f01HLUuwwAAIDBh6tRkVLvBQBy9L-AAHiHf7; ttcid=2e9619ebbb8449eaa3d5a42d8ce88ec835; webcast_leading_last_show_time=1691016922379; webcast_leading_total_show_times=1; webcast_local_quality=sd; live_can_add_dy_2_desktop=%221%22; msToken=1JDHnVPw_9yTvzIrwb7cQj8dCMNOoesXbA_IooV8cezcOdpe4pzusZE7NB7tZn9TBXPr0ylxmv-KMs5rqbNUBHP4P7VBFUu0ZAht_BEylqrLpzgt3y5ne_38hXDOX8o=; msToken=jV_yeN1IQKUd9PlNtpL7k5vthGKcHo0dEh_QPUQhr8G3cuYv-Jbb4NnIxGDmhVOkZOCSihNpA2kvYtHiTW25XNNX_yrsv5FN8O6zm3qmCIXcEe0LywLn7oBO2gITEeg=; tt_scid=mYfqpfbDjqXrIGJuQ7q-DlQJfUSG51qG.KUdzztuGP83OjuVLXnQHjsz-BRHRJu4e986 diff --git a/main.py b/main.py index 6e57e89..9049e2f 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,9 @@ Author: Hmily Github: https://github.com/ihmily Date: 2023-07-17 23:52:05 -Update: 2023-08-03 08:06:43 +Update: 2023-08-04 06:30:00 Copyright (c) 2023 by Hmily, All Rights Reserved. -Function: Record douyin and titok live stream. +Function: Record live stream video. """ import random @@ -55,8 +55,9 @@ name_list = [] firstRunOtherLine = True live_list = [] not_record_list = [] -start5 = datetime.datetime.now() +start5_time = datetime.datetime.now() global_proxy = False +recording_time_list={} headers = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36' } @@ -66,13 +67,15 @@ backup_dir = './backup_config' encoding = 'utf-8-sig' rstr = r"[\/\\\:\*\?\"\<\>\|&u]" ffmpeg_path = "ffmpeg" # ffmpeg文件路径 +default_path = os.getcwd() # --------------------------用到的函数------------------------------------- def display_info(): # TODO: 显示当前录制配置信息 - global start5 + global start5_time + global recording_time_list time.sleep(5) while True: try: @@ -85,25 +88,22 @@ def display_info(): print("配置文件里,直播保存路径并不存在,请重新输入一个正确的路径.或留空表示当前目录,按回车退出") input("程序结束") os._exit(0) - else: - print("视频保存路径: " + video_save_path, end=" | ") - pass + + if use_proxy: + is_use_proxy='是' else: - print("视频保存路径: 当前目录", end=" | ") + is_use_proxy = '否' + print(f"是否开启代理录制: {is_use_proxy}", end=" | ") if Splitvideobysize: print("TS录制分段开启,录制分段大小为 %d M" % Splitsize, end=" | ") - if only_browser: - print("浏览器检测录制", end=" | ") - else: - print("Cookies录制", end=" | ") - + print("Cookies录制", end=" | ") print("录制视频质量为: " + str(video_quality), end=" | ") print("录制视频格式为: " + str(video_save_type), end=" | ") print("目前瞬时错误数为: " + str(warning_count), end=" | ") nowdate = time.strftime("%H:%M:%S", time.localtime()) - print(nowdate) + print(f"当前时间: {nowdate}") if len(recording) == 0 and len(unrecording) == 0: time.sleep(5) @@ -111,17 +111,19 @@ def display_info(): print("") continue else: + now_time = datetime.datetime.now() if len(recording) > 0: print("x" * 60) NoRepeatrecording = list(set(recording)) - print("正在录制{}个直播: ".format(str(len(NoRepeatrecording)))) + print(f"正在录制{len(NoRepeatrecording)}个直播: ") for recording_live in NoRepeatrecording: - print(recording_live + " 正在录制中") - end = datetime.datetime.now() - print('总共录制时间: ' + str(end - start5)) + have_record_time=now_time-recording_time_list[recording_live] + print(f"{recording_live} 正在录制中 "+str(have_record_time).split('.')[0]) + + # print('\n本软件已运行:'+str(now_time - start5_time).split('.')[0]) print("x" * 60) else: - start5 = datetime.datetime.now() + start5_time = now_time except Exception as e: print("错误信息644:" + str(e) + "\r\n发生错误的行数: "+str(e.__traceback__.tb_lineno)) logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno)) @@ -245,13 +247,14 @@ def get_douyin_stream_url(json_data): roomInfo = roomStore['roomInfo'] anchor_name = roomInfo['anchor']['nickname'] data.append(anchor_name) + status=4 # 获取直播间状态 - status = roomInfo["room"]["status"] # 直播状态2是正在直播.4是未开播 + if 'room' in roomInfo: + status = roomInfo["room"]["status"] # 直播状态2是正在直播.4是未开播 if status == 4: - data = [anchor_name, status, '', ''] + data = [anchor_name, False, '', ''] else: - is_login = json_data['app']['odin']['user_is_login'] stream_url = roomInfo['room']['stream_url'] # flv视频流链接 flv_url_list = stream_url['flv_pull_url'] @@ -272,7 +275,7 @@ def get_douyin_stream_url(json_data): m3u8_url = m3u8_url_list["SD2"] flv_url = flv_url_list["SD2"] - data = [anchor_name, status, m3u8_url, flv_url] + data = [anchor_name, True, m3u8_url, flv_url] return data def get_tiktok_stream_url(json_data): @@ -286,7 +289,7 @@ def get_tiktok_stream_url(json_data): status = LiveRoom['user']["status"] # 直播状态2是正在直播.4是未开播 if status == 4: - data = [anchor_name, status, '', ''] + data = [anchor_name, False, '', ''] else: # 画质从高到低:origin>uhd>sd>sd>ld # {origin:'原画质或蓝光',uhd:'1080P或720P',sd:'540P或480P',ld:'360P标清'} @@ -308,16 +311,43 @@ def get_tiktok_stream_url(json_data): # 注意,这里要将链接改为http协议,否则无法使用ffmpeg录制,原因是代理大都是http m3u8_url = re.sub("https", "http", m3u8_url) flv_url = re.sub("https", "http", flv_url) - data = [anchor_name, status, m3u8_url, flv_url] + data = [anchor_name, True, m3u8_url, flv_url] return data +def get_kuaishou_stream_url(json_data): + # TODO: 获取快手直播源地址 + data = [] # 定义一个返回数据列表 + + + liveroom = json_data['liveroom'] + anchor_name = liveroom['author']['name'] + data.append(anchor_name) + # 获取直播间状态 + status = liveroom['isLiving'] # 直播状态True是正在直播.False是未开播 + + if not status: + data = [anchor_name, False, '', ''] + else: + stream_data = liveroom['liveStream']['playUrls'][0]['adaptationSet']['representation'] + # stream_data数组中索引从小到大分别是高清、超清、蓝光4M、蓝光8M (每个直播间不一样) + if video_quality == "原画" or video_quality == "蓝光": + flv_url = stream_data[-1]['url'] + elif video_quality == "超清": + flv_url = stream_data[-2]['url'] + elif video_quality == "高清": + flv_url = stream_data[1]['url'] + elif video_quality == "标清": + flv_url = stream_data[0]['url'] + + data = [anchor_name, True, flv_url, flv_url] # 快手只有flv视频流 + return data def start_record(line, count_variable=-1): global warning_count global video_save_path global live_list global not_record_list - global need_proxy_url_list + global recording_time_list while True: try: record_finished = False @@ -358,6 +388,11 @@ def start_record(line, count_variable=-1): json_data = get_tiktok_stream_data(record_url,proxy_addr) port_info = get_tiktok_stream_url(json_data) + elif record_url.find("https://live.kuaishou.com/") > -1: + with semaphore: + json_data = get_kuaishou_stream_data(record_url) + port_info = get_kuaishou_stream_url(json_data) + # print("端口信息:" + str(port_info)) # port_info=['主播名','状态码','m3u8地址','flv地址'] if len(port_info) != 4: @@ -380,7 +415,7 @@ def start_record(line, count_variable=-1): Runonce = True # 判断状态码 如果是2则正在直播,如果是4则未在直播 - if port_info[1] != 2: + if not port_info[1]: print(f"序号{count_variable} {port_info[0]} 等待直播... ") anchor_name = port_info[0] else: @@ -402,11 +437,13 @@ def start_record(line, count_variable=-1): live_list.append(anchor_name) now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time())) try: + full_path = f'{default_path}/{anchor_name}' if len(video_save_path) > 0: if video_save_path[-1] != "/": video_save_path = video_save_path + "/" - if not os.path.exists(video_save_path + anchor_name): - os.makedirs(video_save_path + anchor_name) + full_path = f'{video_save_path}/{anchor_name}' + if not os.path.exists(full_path): + os.makedirs(full_path) else: if not os.path.exists(anchor_name): os.makedirs('./' + anchor_name) @@ -415,10 +452,9 @@ def start_record(line, count_variable=-1): print("路径错误信息708: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno)) logger.warning("错误信息: " + str(e) + " 发生错误的行数: " + str(e.__traceback__.tb_lineno)) - if not os.path.exists(video_save_path + anchor_name): + if not os.path.exists(full_path): print("保存路径不存在,不能生成录制.请避免把本程序放在c盘,桌面,下载文件夹,qq默认传输目录.请重新检查设置") video_save_path = "" - default_path = os.getcwd() print(f"因为配置文件的路径错误,本次录制在程序目录 {default_path}") @@ -452,27 +488,23 @@ def start_record(line, count_variable=-1): ] # 添加代理参数 - if 'douyin' not in real_url: + if 'tiktok' in real_url: if use_proxy and proxy_addr != '': # os.environ["http_proxy"] = proxy_addr ffmpeg_command.insert(1, "-http_proxy") ffmpeg_command.insert(2, proxy_addr) - recording.add(f'序号{count_variable} ' + anchor_name) + record_name=f'序号{count_variable} ' + anchor_name + recording.add(record_name) + start_record_time = datetime.datetime.now() + recording_time_list[record_name] = start_record_time + rec_info=f"\r{anchor_name} 录制视频中: {full_path}" + filename_short = full_path + '/' + anchor_name + '_' + now if video_save_type == "FLV": filename = anchor_name + '_' + now + '.flv' - - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print( - "\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename) - - - filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now + print(f'{rec_info}/{filename}') if create_time_file: filename_gruop = [anchor_name, filename_short] @@ -484,7 +516,7 @@ def start_record(line, count_variable=-1): try: # “port_info[3]”对应的是flv地址,使用老方法下载(直接请求下载flv)只能是下载flv流的。 real_url = port_info[3] - _filepath, _ = urllib.request.urlretrieve(real_url,video_save_path + anchor_name + '/' + filename) + _filepath, _ = urllib.request.urlretrieve(real_url,full_path + '/' + filename) record_finished = True record_finished_2 = True count_time = time.time() @@ -500,14 +532,8 @@ def start_record(line, count_variable=-1): elif video_save_type == "MKV": filename = anchor_name + '_' + now + ".mkv" - if len(video_save_path) == 0: - print("\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print("\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename) - - file = video_save_path + anchor_name + '/' + filename - filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now - + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename if create_time_file: filename_gruop = [anchor_name, filename_short] create_var[str(filename_short)] = threading.Thread(target=create_ass_file, @@ -540,17 +566,10 @@ def start_record(line, count_variable=-1): unrecording.add(anchor_name) elif video_save_type == "MP4": + filename = anchor_name + '_' + now + ".mp4" - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print( - "\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename) - - file = video_save_path + anchor_name + '/' + filename - - filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename if create_time_file: filename_gruop = [anchor_name, filename_short] @@ -589,14 +608,9 @@ def start_record(line, count_variable=-1): elif video_save_type == "MKV音频": filename = anchor_name + '_' + now + ".mkv" - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 录制MKV音频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print( - "\r" + anchor_name + " 录制MKV音频中: " + video_save_path + anchor_name + '/' + filename) + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename - file = video_save_path + anchor_name + '/' + filename try: command = [ "-map", "0:a", # 不同点 @@ -624,14 +638,9 @@ def start_record(line, count_variable=-1): elif video_save_type == "TS音频": filename = anchor_name + '_' + now + ".ts" - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 录制TS音频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print( - "\r" + anchor_name + " 录制TS音频中: " + video_save_path + anchor_name + '/' + filename) + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename - file = video_save_path + anchor_name + '/' + filename try: command = [ "-map", "0:a", # 不同点 @@ -663,15 +672,8 @@ def start_record(line, count_variable=-1): while True: now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time())) filename = anchor_name + '_' + now + ".ts" - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 分段录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename + " 每录满: %d M 存一个视频" % Splitsize) - else: - print( - "\r" + anchor_name + " 分段录制视频中: " + video_save_path + anchor_name + '/' + filename + " 每录满: %d M 存一个视频" % Splitsize) - - file = video_save_path + anchor_name + '/' + filename - filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename if create_time_file: filename_gruop = [anchor_name, filename_short] @@ -718,15 +720,9 @@ def start_record(line, count_variable=-1): else: filename = anchor_name + '_' + now + ".ts" - if len(video_save_path) == 0: - print( - "\r" + anchor_name + " 录制视频中: " + os.getcwd() + "/" + anchor_name + '/' + filename) - else: - print( - "\r" + anchor_name + " 录制视频中: " + video_save_path + anchor_name + '/' + filename) - file = video_save_path + anchor_name + '/' + filename - filename_short = video_save_path + anchor_name + '/' + anchor_name + '_' + now + print(f'{rec_info}/{filename}') + file = full_path + '/' + filename if create_time_file: filename_gruop = [anchor_name, filename_short] @@ -955,8 +951,6 @@ while True: tsconvert_to_m4a = read_config_value(config, '1', 'TS录制完成后自动增加生成m4a格式', "否") delFilebeforeconversion = read_config_value(config, '1', '追加格式后删除原文件', "否") create_time_file = read_config_value(config, '1', '生成时间文件', "否") - display_chrome = read_config_value(config, '1', '是否显示浏览器', "否") - only_browser = read_config_value(config, '1', '仅用浏览器录制', "否") cookies_set = read_config_value(config, '1', 'cookies(不可为空)', '') if len(video_save_type) > 0: @@ -1005,14 +999,11 @@ while True: loop_time = options.get(loop_time, False) # 是否显示循环秒数 Splitvideobysize = options.get(Splitvideobysize, False) # 这里是控制TS是否分段 create_time_file = options.get(create_time_file, False) # 这里控制是否生成时间文件 - display_chrome = options.get(display_chrome, False) # 这里控制是否生显示浏览器 - only_browser = options.get(only_browser, False) # 这里是控制采用浏览器录制 delFilebeforeconversion = options.get(delFilebeforeconversion, False) # 追加格式后,是否删除原文件 tsconvert_to_m4a = options.get(tsconvert_to_m4a, False) # 这里是控制TS是否追加m4a格式 tsconvert_to_mp4 = options.get(tsconvert_to_mp4, False) # 这里是控制TS是否追加mp4格式 - # 读取url_config.ini文件 try: with open(url_config_file, "r", encoding=encoding) as file: @@ -1027,7 +1018,7 @@ while True: split_line = [line, ''] url = split_line[0] url_host=url.split('/')[2] - host_list=['live.douyin.com','v.douyin.com','www.tiktok.com'] + host_list=['live.douyin.com','v.douyin.com','www.tiktok.com','live.kuaishou.com'] if url_host in host_list: new_line = (url, split_line[1]) url_tuples_list.append(new_line) @@ -1058,7 +1049,6 @@ while True: create_var['thread' + str(Monitoring)].daemon = True create_var['thread' + str(Monitoring)].start() runing_list.append(url_tuple[0]) - # print("\r"+str(local_delay_default)+" 秒后读取下一个地址(如果存在) ") time.sleep(local_delay_default) url_tuples_list = [] first_start = False diff --git a/spider.py b/spider.py index 4287a4d..a16b23b 100644 --- a/spider.py +++ b/spider.py @@ -4,9 +4,9 @@ Author: Hmily Github:https://github.com/ihmily Date: 2023-07-15 23:15:00 -Update: 2023-08-03 08:06:43 +Update: 2023-08-04 06:30:00 Copyright (c) 2023 by Hmily, All Rights Reserved. -Function: Get douyin and titok live stream. +Function: Get live stream data. """ import urllib import urllib.parse @@ -14,14 +14,13 @@ import requests import re import json -# 直接选择从网页HTML中获取直播间数据 -def get_douyin_stream_data(url,cookies): +# 直接选择从网页HTML中获取直播间数据 +def get_douyin_stream_data(url, cookies): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Referer': 'https://live.douyin.com/', - # 'Cookie':'ttwid=1^%^7CIkooT8SJQrpeYtHlSALuhz9BdcHpaaf9tHQRKHuDaYE^%^7C1687785070^%^7C6690250483b63b6482128174d0f93bd879614d76f1b6e03ca52e032cf7fbaafd; passport_csrf_token=52bece134ac246c81163cc93b72f86a6; passport_csrf_token_default=52bece134ac246c81163cc93b72f86a6; d_ticket=2b9e3eb3626216c0122f0d980f867deb7b414; odin_tt=36dcfa4bd95b1edf0e6445dc9584a7371b4b90a2a8c390292b9be44af8161e06d10e34e6e575bf43c45c0a5871229533; passport_assist_user=CjxqZLHwcDmhxMjoh8u0-Jz4Zmhcq9VzKQqpAjK3P9Ve87i4njjbsai_u6NAI6MebG4KH4QXtbfNRbRFWRgaSAo8oBvHC_eXhqSGSo1uWPz4KBGu9uo-UdwM-5ynbDuDQRybofj0pQlPexcYmVoryiYqpC7yMdKO4rSVclgNEJbxtA0Yia_WVCIBA78Lg84^%^3D; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; passport_auth_status=a74f300f376940d65914eb148d55ca96^%^2C9ca487aea255972120d502f736c5dd7b; passport_auth_status_ss=a74f300f376940d65914eb148d55ca96^%^2C9ca487aea255972120d502f736c5dd7b; sso_auth_status=52ecac30d95890cc7896c880366aa21a; sso_auth_status_ss=52ecac30d95890cc7896c880366aa21a; sso_uid_tt=a71f659bc416b890eb13929ee82a4340; sso_uid_tt_ss=a71f659bc416b890eb13929ee82a4340; toutiao_sso_user=da6c1f563492114cf1ad2dac7617e3f4; toutiao_sso_user_ss=da6c1f563492114cf1ad2dac7617e3f4; sid_ucp_sso_v1=1.0.0-KDNhOTk2NzYzZjkzMGZkZDdlNDU4ODE3YjczNGE3MGExYTBhOGQ0OGIKHQjRpfzk8AEQn6LmpAYY7zEgDDCRxffLBTgCQPEHGgJsZiIgZGE2YzFmNTYzNDkyMTE0Y2YxYWQyZGFjNzYxN2UzZjQ; ssid_ucp_sso_v1=1.0.0-KDNhOTk2NzYzZjkzMGZkZDdlNDU4ODE3YjczNGE3MGExYTBhOGQ0OGIKHQjRpfzk8AEQn6LmpAYY7zEgDDCRxffLBTgCQPEHGgJsZiIgZGE2YzFmNTYzNDkyMTE0Y2YxYWQyZGFjNzYxN2UzZjQ; sid_guard=219f9f2d8838724307589f32debd7d62^%^7C1687785774^%^7C5183988^%^7CFri^%^2C+25-Aug-2023+13^%^3A22^%^3A42+GMT; uid_tt=9f33ebaf781ad75909d6d4edb0b46b86; uid_tt_ss=9f33ebaf781ad75909d6d4edb0b46b86; sid_tt=219f9f2d8838724307589f32debd7d62; sessionid=219f9f2d8838724307589f32debd7d62; sessionid_ss=219f9f2d8838724307589f32debd7d62; sid_ucp_v1=1.0.0-KGZkMzE1MGRhMTZiOTI4M2ZkOTkzMjIwNjQ5NmJhMjhjMzlhZmFmMGYKGQjRpfzk8AEQrqLmpAYY7zEgDDgCQPEHSAQaAmxmIiAyMTlmOWYyZDg4Mzg3MjQzMDc1ODlmMzJkZWJkN2Q2Mg; ssid_ucp_v1=1.0.0-KGZkMzE1MGRhMTZiOTI4M2ZkOTkzMjIwNjQ5NmJhMjhjMzlhZmFmMGYKGQjRpfzk8AEQrqLmpAYY7zEgDDgCQPEHSAQaAmxmIiAyMTlmOWYyZDg4Mzg3MjQzMDc1ODlmMzJkZWJkN2Q2Mg; LOGIN_STATUS=1; store-region=cn-fj; store-region-src=uid; __security_server_data_status=1; __live_version__=^%^221.1.1.1250^%^22; live_can_add_dy_2_desktop=^%^220^%^22; xgplayer_user_id=528819598596; publish_badge_show_info=^%^220^%^2C0^%^2C0^%^2C1689195658062^%^22; msToken=OqErXe8WFLs1OjcJCNX2pNWTvnMSJIKjUXQRa74H4uQo8Ea5hpI8L3zlpK2eq5GUyrHcnTbQ-Kw4UgEntfb9dXu4Ijfowp_LSMxN6AISaoDf-OZCFv2IFS1P4UY2DHYG; ttcid=b8ea42abb1954fd2a913086620d2447f25; download_guide=^%^223^%^2F20230713^%^2F0^%^22; home_can_add_dy_2_desktop=^%^220^%^22; strategyABtestKey=^%^221689299939.836^%^22; FOLLOW_LIVE_POINT_INFO=^%^22MS4wLjABAAAAf6aekfyBsc4u8jMkeYbgnkFa0ksIWKWpGOywuyHXyo4^%^2F1689350400000^%^2F0^%^2F1689299940112^%^2F0^%^22; VIDEO_FILTER_MEMO_SELECT=^%^7B^%^22expireTime^%^22^%^3A1689904741009^%^2C^%^22type^%^22^%^3Anull^%^7D; device_web_cpu_core=8; device_web_memory_size=-1; webcast_local_quality=origin; csrf_session_id=ce1e9bc7ba69feec32889636027ce79a; passport_fe_beating_status=false; webcast_leading_last_show_time=1689300023141; webcast_leading_total_show_times=1; tt_scid=PgQO8z6aK2zeofuxFGselkNp2kSbPFCuPmOMwU9ih.SXbBp8iA7l2EiqrurdBuMWf204; msToken=T5-gdGi61ytJtas2VgUQAogURSJT2pQDWT5E_TPGT9paO9OtCuHOGAl72YAxHhrkKJdNhx6O1JgGn0uzdkfHw_a_MWJS-OJlgroduiLAcJzzSCmib6GfWqIgWT8m2qA3; __ac_nonce=064b0be450072f85a1215; __ac_signature=_02B4Z6wo00f01eL3lWgAAIDA.rQr1mcyUx3ixpHAABwPwM4wuxfDlht-h5js2proCQ84O246NPRhh7I6Pv0tJwHeCCotGZpibWazzH51O7kDcl18lUJy6o8VYLGIG..jFlP-zEpspGjM6AZO34; __ac_referer=https://live.douyin.com/', 'Cookie': cookies } @@ -38,12 +37,12 @@ def get_douyin_stream_data(url,cookies): return json_data -def get_tiktok_stream_data(url,proxy_addr): +def get_tiktok_stream_data(url, proxy_addr): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.79' } - if proxy_addr !='': + if proxy_addr != '': # 设置代理 proxies = { 'http': proxy_addr, @@ -67,10 +66,27 @@ def get_tiktok_stream_data(url,proxy_addr): return json_data +def get_kuaishou_stream_data(url): + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', + } + + request = urllib.request.Request(url, headers=headers) + response = urllib.request.urlopen(request, timeout=10) + html_str = response.read().decode('utf-8') + json_str = re.findall('__INITIAL_STATE__=(.*?);\(function', html_str)[0] + # print(json_str) + json_data = json.loads(json_str) + return json_data + + if __name__ == '__main__': - Cookie='ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511; my_rd=1; passport_csrf_token=3ab34460fa656183fccfb904b16ff742; passport_csrf_token_default=3ab34460fa656183fccfb904b16ff742; d_ticket=9f562383ac0547d0b561904513229d76c9c21; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; store-region=cn-fj; store-region-src=uid; LOGIN_STATUS=1; __security_server_data_status=1; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; pwa2=%223%7C0%7C3%7C0%22; download_guide=%223%2F20230729%2F0%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.6%7D; strategyABtestKey=%221690824679.923%22; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; VIDEO_FILTER_MEMO_SELECT=%7B%22expireTime%22%3A1691443863751%2C%22type%22%3Anull%7D; home_can_add_dy_2_desktop=%221%22; __live_version__=%221.1.1.2169%22; device_web_cpu_core=8; device_web_memory_size=8; xgplayer_user_id=346045893336; csrf_session_id=2e00356b5cd8544d17a0e66484946f28; odin_tt=724eb4dd23bc6ffaed9a1571ac4c757ef597768a70c75fef695b95845b7ffcd8b1524278c2ac31c2587996d058e03414595f0a4e856c53bd0d5e5f56dc6d82e24004dc77773e6b83ced6f80f1bb70627; __ac_nonce=064caded4009deafd8b89; __ac_signature=_02B4Z6wo00f01HLUuwwAAIDBh6tRkVLvBQBy9L-AAHiHf7; ttcid=2e9619ebbb8449eaa3d5a42d8ce88ec835; webcast_leading_last_show_time=1691016922379; webcast_leading_total_show_times=1; webcast_local_quality=sd; live_can_add_dy_2_desktop=%221%22; msToken=1JDHnVPw_9yTvzIrwb7cQj8dCMNOoesXbA_IooV8cezcOdpe4pzusZE7NB7tZn9TBXPr0ylxmv-KMs5rqbNUBHP4P7VBFUu0ZAht_BEylqrLpzgt3y5ne_38hXDOX8o=; msToken=jV_yeN1IQKUd9PlNtpL7k5vthGKcHo0dEh_QPUQhr8G3cuYv-Jbb4NnIxGDmhVOkZOCSihNpA2kvYtHiTW25XNNX_yrsv5FN8O6zm3qmCIXcEe0LywLn7oBO2gITEeg=; tt_scid=mYfqpfbDjqXrIGJuQ7q-DlQJfUSG51qG.KUdzztuGP83OjuVLXnQHjsz-BRHRJu4e986' - url="https://live.douyin.com/803023607352" # douyin live - url="https://live.douyin.com/745964462470" # douyin live - # url = "https://www.tiktok.com/@pearlgaga88/live" # tiktok live - print(get_douyin_stream_data(url,Cookie)) - # print(get_tiktok_stream_data(url,'')) \ No newline at end of file + # 抖音直播间页面的cookie + Cookie = 'ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511; my_rd=1; passport_csrf_token=3ab34460fa656183fccfb904b16ff742; passport_csrf_token_default=3ab34460fa656183fccfb904b16ff742; d_ticket=9f562383ac0547d0b561904513229d76c9c21; n_mh=hvnJEQ4Q5eiH74-84kTFUyv4VK8xtSrpRZG1AhCeFNI; store-region=cn-fj; store-region-src=uid; LOGIN_STATUS=1; __security_server_data_status=1; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; pwa2=%223%7C0%7C3%7C0%22; download_guide=%223%2F20230729%2F0%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.6%7D; strategyABtestKey=%221690824679.923%22; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A150%7D%22; VIDEO_FILTER_MEMO_SELECT=%7B%22expireTime%22%3A1691443863751%2C%22type%22%3Anull%7D; home_can_add_dy_2_desktop=%221%22; __live_version__=%221.1.1.2169%22; device_web_cpu_core=8; device_web_memory_size=8; xgplayer_user_id=346045893336; csrf_session_id=2e00356b5cd8544d17a0e66484946f28; odin_tt=724eb4dd23bc6ffaed9a1571ac4c757ef597768a70c75fef695b95845b7ffcd8b1524278c2ac31c2587996d058e03414595f0a4e856c53bd0d5e5f56dc6d82e24004dc77773e6b83ced6f80f1bb70627; __ac_nonce=064caded4009deafd8b89; __ac_signature=_02B4Z6wo00f01HLUuwwAAIDBh6tRkVLvBQBy9L-AAHiHf7; ttcid=2e9619ebbb8449eaa3d5a42d8ce88ec835; webcast_leading_last_show_time=1691016922379; webcast_leading_total_show_times=1; webcast_local_quality=sd; live_can_add_dy_2_desktop=%221%22; msToken=1JDHnVPw_9yTvzIrwb7cQj8dCMNOoesXbA_IooV8cezcOdpe4pzusZE7NB7tZn9TBXPr0ylxmv-KMs5rqbNUBHP4P7VBFUu0ZAht_BEylqrLpzgt3y5ne_38hXDOX8o=; msToken=jV_yeN1IQKUd9PlNtpL7k5vthGKcHo0dEh_QPUQhr8G3cuYv-Jbb4NnIxGDmhVOkZOCSihNpA2kvYtHiTW25XNNX_yrsv5FN8O6zm3qmCIXcEe0LywLn7oBO2gITEeg=; tt_scid=mYfqpfbDjqXrIGJuQ7q-DlQJfUSG51qG.KUdzztuGP83OjuVLXnQHjsz-BRHRJu4e986' + url = "https://live.douyin.com/745964462470" # 抖音直播 + # url = "https://www.tiktok.com/@pearlgaga88/live" # Tiktok 直播 + # url = "https://live.kuaishou.com/u/yall1102" # 快手直播 + # print(get_douyin_stream_data(url,Cookie)) + # print(get_tiktok_stream_data(url,'')) + # print(get_kuaishou_stream_data(url))