feat(tiktok): 增加配置文件, 手动传入自己的cookie

fix #16
This commit is contained in:
imgyh 2023-03-28 17:21:04 +08:00
parent 9fc37f1048
commit ec559e2913
2 changed files with 299 additions and 54 deletions

View File

@ -16,17 +16,40 @@ Change Log :
import argparse import argparse
import os import os
import json import json
import yaml
import time
from TikTok import TikTok from TikTok import TikTok
from TikTokUtils import Utils from TikTokUtils import Utils
configModel = {
"link": [],
"path": os.getcwd(),
"music": True,
"cover": True,
"avatar": True,
"json": True,
"mode": ["post"],
"number": {
"post": 0,
"like": 0,
"allmix": 0,
"mix": 0,
"music": 0,
},
"thread": 5,
"cookie": None
}
def argument(): def argument():
parser = argparse.ArgumentParser(description='抖音批量下载工具 使用帮助') parser = argparse.ArgumentParser(description='抖音批量下载工具 使用帮助')
parser.add_argument("--cmd", "-C", help="使用命令行(True)或者配置文件(False), 默认为False",
type=Utils().str2bool, required=False, default=False)
parser.add_argument("--link", "-l", parser.add_argument("--link", "-l",
help="作品(视频或图集)、直播、合集、音乐集合、个人主页的分享链接或者电脑浏览器网址(删除文案, 保证只有URL, https://v.douyin.com/kcvMpuN/ 或者 https://www.douyin.com/开头的)", help="作品(视频或图集)、直播、合集、音乐集合、个人主页的分享链接或者电脑浏览器网址, 可以设置多个链接(删除文案, 保证只有URL, https://v.douyin.com/kcvMpuN/ 或者 https://www.douyin.com/开头的)",
type=str, required=True) type=str, required=False, default=[], action="append")
parser.add_argument("--path", "-p", help="下载保存位置", parser.add_argument("--path", "-p", help="下载保存位置, 默认当前文件位置",
type=str, required=True) type=str, required=False,default=os.getcwd())
parser.add_argument("--music", "-m", help="是否下载视频中的音乐(True/False), 默认为True", parser.add_argument("--music", "-m", help="是否下载视频中的音乐(True/False), 默认为True",
type=Utils().str2bool, required=False, default=True) type=Utils().str2bool, required=False, default=True)
parser.add_argument("--cover", "-c", help="是否下载视频的封面(True/False), 默认为True, 当下载视频时有效", parser.add_argument("--cover", "-c", help="是否下载视频的封面(True/False), 默认为True, 当下载视频时有效",
@ -35,72 +58,213 @@ def argument():
type=Utils().str2bool, required=False, default=True) type=Utils().str2bool, required=False, default=True)
parser.add_argument("--json", "-j", help="是否保存获取到的数据(True/False), 默认为True", parser.add_argument("--json", "-j", help="是否保存获取到的数据(True/False), 默认为True",
type=Utils().str2bool, required=False, default=True) type=Utils().str2bool, required=False, default=True)
parser.add_argument("--mode", "-M", help="link是个人主页时, 设置下载发布的作品(post)或喜欢的作品(like)或者用户所有合集(mix), 默认为post", parser.add_argument("--mode", "-M", help="link是个人主页时, 设置下载发布的作品(post)或喜欢的作品(like)或者用户所有合集(mix), 默认为post, 可以设置多种模式",
type=str, required=False, default="post") type=str, required=False, default=["post"], action="append")
parser.add_argument("--number", "-n", parser.add_argument("--postnumber", help="主页下作品下载个数设置, 默认为0 全部下载",
help="1.当下载单个合集、音乐集合、主页作品(post模式)和喜欢(like模式)时, 可设置下载前n个作品, 默认为0全部下载\r\n" + type=int, required=False, default=0)
"2.当下载主页下所有合集(mix模式)时, 设置下载前n个合集下所有作品, 默认为0全部下载", parser.add_argument("--likenumber", help="主页下喜欢下载个数设置, 默认为0 全部下载",
type=int, required=False, default=0)
parser.add_argument("--allmixnumber", help="主页下合集下载个数设置, 默认为0 全部下载",
type=int, required=False, default=0)
parser.add_argument("--mixnumber", help="单个合集下作品下载个数设置, 默认为0 全部下载",
type=int, required=False, default=0)
parser.add_argument("--musicnumber", help="音乐(原声)下作品下载个数设置, 默认为0 全部下载",
type=int, required=False, default=0) type=int, required=False, default=0)
parser.add_argument("--thread", "-t", parser.add_argument("--thread", "-t",
help="设置线程数, 默认5个线程", help="设置线程数, 默认5个线程",
type=int, required=False, default=5) type=int, required=False, default=5)
parser.add_argument("--cookie", help="设置cookie, 格式: \"name1=value1; name2=value2;\" 注意要加冒号",
type=str, required=False, default='')
args = parser.parse_args() args = parser.parse_args()
if args.thread <= 0:
args.thread = 5
return args return args
def yamlConfig():
curPath = os.path.dirname(os.path.abspath(__file__))
yamlPath = os.path.join(curPath, "config.yml")
f = open(yamlPath, 'r', encoding='utf-8')
cfg = f.read()
configDict = yaml.load(stream=cfg,Loader=yaml.FullLoader)
try:
configModel["link"] = configDict["link"]
except Exception as e:
print("[ 警告 ]:link未设置, 程序退出...\r\n")
try:
configModel["path"] = configDict["path"]
except Exception as e:
print("[ 警告 ]:path未设置, 使用当前路径...\r\n")
try:
configModel["music"] = configDict["music"]
except Exception as e:
print("[ 警告 ]:music未设置, 使用默认值True...\r\n")
try:
configModel["cover"] = configDict["cover"]
except Exception as e:
print("[ 警告 ]:cover未设置, 使用默认值True...\r\n")
try:
configModel["avatar"] = configDict["avatar"]
except Exception as e:
print("[ 警告 ]:avatar未设置, 使用默认值True...\r\n")
try:
configModel["json"] = configDict["json"]
except Exception as e:
print("[ 警告 ]:json未设置, 使用默认值True...\r\n")
try:
configModel["mode"] = configDict["mode"]
except Exception as e:
print("[ 警告 ]:mode未设置, 使用默认值post...\r\n")
try:
configModel["number"]["post"] = configDict["number"]["post"]
except Exception as e:
print("[ 警告 ]:post number未设置, 使用默认值0...\r\n")
try:
configModel["number"]["like"] = configDict["number"]["like"]
except Exception as e:
print("[ 警告 ]:like number未设置, 使用默认值0...\r\n")
try:
configModel["number"]["allmix"] = configDict["number"]["allmix"]
except Exception as e:
print("[ 警告 ]:allmix number未设置, 使用默认值0...\r\n")
try:
configModel["number"]["mix"] = configDict["number"]["mix"]
except Exception as e:
print("[ 警告 ]:mix number未设置, 使用默认值0...\r\n")
try:
configModel["number"]["music"] = configDict["number"]["music"]
except Exception as e:
print("[ 警告 ]:music number未设置, 使用默认值0...\r\n")
try:
configModel["thread"] = configDict["thread"]
except Exception as e:
print("[ 警告 ]:thread未设置, 使用默认值5...\r\n")
try:
cookiekey = configDict["cookies"].keys()
cookieStr = ""
for i in cookiekey:
cookieStr = cookieStr + i + "=" + configDict["cookies"][i] + "; "
configModel["cookie"] = cookieStr
except Exception as e:
pass
try:
configModel["cookie"] = configDict["cookie"]
except Exception as e:
pass
def main(): def main():
start = time.time() # 开始时间
utils = Utils() utils = Utils()
args = argument() args = argument()
tk = TikTok()
url = tk.getShareLink(args.link) if args.cmd:
key_type, key = tk.getKey(url) configModel["link"] = args.link
if args.thread <= 0: configModel["path"] = args.path
args.thread = 5 configModel["music"] = args.music
if key is None or key_type is None: configModel["cover"] = args.cover
configModel["avatar"] = args.avatar
configModel["json"] = args.json
configModel["mode"] = args.mode
configModel["number"]["post"] = args.postnumber
configModel["number"]["like"] = args.likenumber
configModel["number"]["allmix"] = args.allmixnumber
configModel["number"]["mix"] = args.mixnumber
configModel["number"]["music"] = args.musicnumber
configModel["thread"] = args.thread
configModel["cookie"] = args.cookie
else:
yamlConfig()
if configModel["link"] == []:
return return
elif key_type == "user" and args.mode != 'mix':
datalist = tk.getUserInfo(key, args.mode, 35, args.number)
tk.userDownload(awemeList=datalist, music=args.music, cover=args.cover, avatar=args.avatar, resjson=args.json,
savePath=args.path, thread=args.thread)
elif key_type == "user" and args.mode == 'mix':
if not os.path.exists(args.path):
os.mkdir(args.path)
mixIdNameDict = tk.getUserAllMixInfo(key, 35, args.number)
for mix_id in mixIdNameDict: tk = TikTok()
print(f'[ 提示 ]:正在下载合集 [{mixIdNameDict[mix_id]}] 中的作品\r\n') tk.headers["Cookie"] = configModel["cookie"]
mix_file_name = utils.replaceStr(mixIdNameDict[mix_id])
datalist = tk.getMixInfo(mix_id, 35)
tk.userDownload(awemeList=datalist, music=args.music, cover=args.cover, avatar=args.avatar, resjson=args.json,
savePath=os.path.join(args.path, mix_file_name), thread=args.thread)
print(f'[ 提示 ]:合集 [{mixIdNameDict[mix_id]}] 中的作品下载完成\r\n')
elif key_type == "mix":
datalist = tk.getMixInfo(key,35, args.number)
tk.userDownload(awemeList=datalist, music=args.music, cover=args.cover, avatar=args.avatar, resjson=args.json,
savePath=args.path, thread=args.thread)
elif key_type == "music":
datalist = tk.getMusicInfo(key,35, args.number)
tk.userDownload(awemeList=datalist, music=args.music, cover=args.cover, avatar=args.avatar, resjson=args.json,
savePath=args.path, thread=args.thread)
elif key_type == "aweme":
datanew, dataraw = tk.getAwemeInfo(key)
datalist = []
datalist.append(datanew)
tk.userDownload(awemeList=datalist, music=args.music, cover=args.cover, avatar=args.avatar, resjson=args.json,
savePath=args.path, thread=args.thread)
elif key_type == "live":
live_json = tk.getLiveInfo(key)
if args.json:
if not os.path.exists(args.path):
os.mkdir(args.path)
# 保存获取到json if not os.path.exists(configModel["path"]):
print("[ 提示 ]:正在保存获取到的信息到result.json\r\n") os.mkdir(configModel["path"])
with open(os.path.join(args.path, "result.json"), "w", encoding='utf-8') as f:
f.write(json.dumps(live_json, ensure_ascii=False, indent=2))
f.close()
for link in configModel["link"]:
print("[ 提示 ]:正在请求的链接: " + link + "\r\n")
url = tk.getShareLink(link)
key_type, key = tk.getKey(url)
if key_type == "user":
userPath = os.path.join(configModel["path"], "user_"+key)
if not os.path.exists(userPath):
os.mkdir(userPath)
for mode in configModel["mode"]:
if mode == 'post' or mode == 'like':
datalist = tk.getUserInfo(key, mode, 35, configModel["number"][mode])
if datalist is not None and datalist != []:
modePath = os.path.join(userPath, mode)
if not os.path.exists(modePath):
os.mkdir(modePath)
tk.userDownload(awemeList=datalist, music=configModel["music"], cover=configModel["cover"],
avatar=configModel["avatar"], resjson=configModel["json"],
savePath=modePath, thread=configModel["thread"])
elif mode == 'mix':
mixIdNameDict = tk.getUserAllMixInfo(key, 35, configModel["number"]["allmix"])
if mixIdNameDict is not None and mixIdNameDict != {}:
for mix_id in mixIdNameDict:
print(f'[ 提示 ]:正在下载合集 [{mixIdNameDict[mix_id]}] 中的作品\r\n')
mix_file_name = utils.replaceStr(mixIdNameDict[mix_id])
datalist = tk.getMixInfo(mix_id, 35)
if datalist is not None and datalist != []:
modePath = os.path.join(userPath, mode)
if not os.path.exists(modePath):
os.mkdir(modePath)
tk.userDownload(awemeList=datalist, music=configModel["music"], cover=configModel["cover"],
avatar=configModel["avatar"], resjson=configModel["json"],
savePath=os.path.join(modePath, mix_file_name), thread=configModel["thread"])
print(f'[ 提示 ]:合集 [{mixIdNameDict[mix_id]}] 中的作品下载完成\r\n')
elif key_type == "mix":
datalist = tk.getMixInfo(key,35, configModel["number"]["mix"])
if datalist is not None and datalist != []:
mixPath = os.path.join(configModel["path"], "mix_" + key)
if not os.path.exists(mixPath):
os.mkdir(mixPath)
tk.userDownload(awemeList=datalist, music=configModel["music"], cover=configModel["cover"],
avatar=configModel["avatar"], resjson=configModel["json"],
savePath=mixPath, thread=configModel["thread"])
elif key_type == "music":
datalist = tk.getMusicInfo(key,35, configModel["number"]["music"])
if datalist is not None and datalist != []:
musicPath = os.path.join(configModel["path"], "music_" + key)
if not os.path.exists(musicPath):
os.mkdir(musicPath)
tk.userDownload(awemeList=datalist, music=configModel["music"], cover=configModel["cover"],
avatar=configModel["avatar"], resjson=configModel["json"],
savePath=musicPath, thread=configModel["thread"])
elif key_type == "aweme":
datanew, dataraw = tk.getAwemeInfo(key)
if datanew is not None and datanew != {}:
datalist = []
datalist.append(datanew)
awemePath = os.path.join(configModel["path"], "aweme")
if not os.path.exists(awemePath):
os.mkdir(awemePath)
tk.userDownload(awemeList=datalist, music=configModel["music"], cover=configModel["cover"],
avatar=configModel["avatar"], resjson=configModel["json"],
savePath=awemePath, thread=configModel["thread"])
elif key_type == "live":
live_json = tk.getLiveInfo(key)
if configModel["json"]:
livePath = os.path.join(configModel["path"], "live")
if not os.path.exists(livePath):
os.mkdir(livePath)
live_file_name = utils.replaceStr(key + live_json["nickname"])
# 保存获取到json
print("[ 提示 ]:正在保存获取到的信息到result.json\r\n")
with open(os.path.join(livePath, live_file_name + ".json"), "w", encoding='utf-8') as f:
f.write(json.dumps(live_json, ensure_ascii=False, indent=2))
f.close()
end = time.time() # 结束时间
print('\n' + '[下载完成]:总耗时: %d分钟%d\n' % (int((end - start) / 60), ((end - start) % 60))) # 输出下载用时时间
if __name__ == "__main__": if __name__ == "__main__":
main() main()

81
config.yml Normal file
View File

@ -0,0 +1,81 @@
#######################################
# 说明:
# 1. 井号(#)为注释
# 2. 缩进严格对齐,使用空格缩进, 注意有些冒号后面有一个空格, 有些没有空格
# 3. 请使用英文字符
# 4. 更多yaml语法请上网查看
#######################################
# 作品(视频或图集)、直播、合集、音乐集合、个人主页的分享链接或者电脑浏览器网址
# (删除文案, 保证只有URL, https://v.douyin.com/kcvMpuN/ 或者 https://www.douyin.com/开头的)
# 可以设置多个链接, 确保至少一个链接
# 必选
link:
- https://live.douyin.com/759547612580
- https://v.douyin.com/BugmVVD/
- https://v.douyin.com/BugrFTN/
- https://v.douyin.com/B72pdU5/
- https://v.douyin.com/B72QgDw/
- https://v.douyin.com/AJp8D3f/
- https://v.douyin.com/B38oovu/
- https://v.douyin.com/S6YMNXs/
# 下载保存位置, 默认当前文件位置
# 必选
path: /mnt/c/project/test333
# 是否下载视频中的音乐(True/False), 默认为True
# 可选
music: True
# 是否下载视频的封面(True/False), 默认为True, 当下载视频时有效
# 可选
cover: True
# 是否下载作者的头像(True/False), 默认为True
# 可选
avatar: True
# 是否保存获取到的数据(True/False), 默认为True
# 可选
json: True
# link是个人主页时, 设置下载发布的作品(post)或喜欢的作品(like)或者用户所有合集(mix), 默认为post, 可以设置多种模式
# 可选
mode:
- post
- like
- mix
# 下载作品个数设置
# 可选
number:
post: 5 # 主页下作品下载个数设置, 默认为0 全部下载
like: 5 # 主页下喜欢下载个数设置, 默认为0 全部下载
allmix: 1 # 主页下合集下载个数设置, 默认为0 全部下载
mix: 5 # 单个合集下作品下载个数设置, 默认为0 全部下载
music: 5 # 音乐(原声)下作品下载个数设置, 默认为0 全部下载
# 设置线程数, 默认5个线程
# 可选
thread: 5
# cookie 请登录网页抖音后F12查看
# cookies 和 cookie 二选一, 要使用这种形式, 请注释下面的cookie
# 目前只需要msToken、ttwid、odin_tt、passport_csrf_token、sid_guard
# 可以动态添加, 程序会根据填的键查找,并没有写死, 如果抖音需要更多的cookie自己加上就行了
cookies:
msToken: xxx
ttwid: xxx
odin_tt: xxx
passport_csrf_token: xxx
sid_guard: xxx
# cookie 请登录网页抖音后F12查看
# cookies 和 cookie 二选一, 要使用这种形式, 请注释上面的cookies及包含的所有键值对
# 设置了这个后上面的cookies选项自动失效, 这个优先级更高
# 格式: "name1=value1; name2=value2;" 注意要加冒号
# 冒号中的内容包括不限于以下键值对, 如果抖音需要更多的cookie自己加上就行了
#cookie: "msToken=xxx; ttwid=xxx; odin_tt=xxx; passport_csrf_token=xxx; sid_guard=xxx;"