python3下载抖音视频的完整代码


Posted in Python onJune 05, 2019

python3下载抖音视频的代码如下所示:

# -*- coding:utf-8 -*-
from contextlib import closing
import requests, json, re, os, sys, random
from ipaddress import ip_address
from subprocess import Popen, PIPE
import urllib
class DouYin(object):
 def __init__(self, width = 500, height = 300):
 """
 抖音App视频下载
 """
 rip = ip_address('0.0.0.0')
 while rip.is_private:
  rip = ip_address('.'.join(map(str, (random.randint(0, 255) for _ in range(4)))))
 self.headers = {
  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'zh-CN,zh;q=0.9',
  'pragma': 'no-cache',
  'cache-control': 'no-cache',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; MI 4S Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.1.3',
  'X-Real-IP': str(rip),
  'X-Forwarded-For': str(rip),
 }
 def get_video_urls(self, user_id, type_flag='f'):
 """
 获得视频播放地址
 Parameters:
  user_id:查询的用户UID
 Returns:
  video_names: 视频名字列表
  video_urls: 视频链接列表
  nickname: 用户昵称
 """
 video_names = []
 video_urls = []
 share_urls = []
 max_cursor = 0
 has_more = 1
 i = 0
 share_user_url = 'https://www.douyin.com/share/user/%s' % user_id
 share_user = requests.get(share_user_url, headers=self.headers)
 while share_user.status_code != 200:
  share_user = requests.get(share_user_url, headers=self.headers)
 _dytk_re = re.compile(r"dytk\s*:\s*'(.+)'")
 dytk = _dytk_re.search(share_user.text).group(1)
 _nickname_re = re.compile(r'<p class="nickname">(.+?)<\/p>')
 nickname = _nickname_re.search(share_user.text).group(1)
 urllib.request.urlretrieve('https://raw.githubusercontent.com/Jack-Cherish/python-spider/master/douyin/fuck-byted-acrawler.js', 'fuck-byted-acrawler.js')
 try:
  Popen(['node', '-v'], stdout=PIPE, stderr=PIPE).communicate()
 except (OSError, IOError) as err:
  print('请先安装 node.js: https://nodejs.org/')
  sys.exit()
 user_url_prefix = 'https://www.douyin.com/aweme/v1/aweme/favorite' if type_flag == 'f' else 'https://www.douyin.com/aweme/v1/aweme/post'
 print('解析视频链接中')
 while has_more != 0:
  process = Popen(['node', 'fuck-byted-acrawler.js', str(user_id)], stdout=PIPE, stderr=PIPE)
  _sign = process.communicate()[0].decode().strip('\n').strip('\r')
  user_url = user_url_prefix + '/?user_id=%s&max_cursor=%s&count=21&aid=1128&_signature=%s&dytk=%s' % (user_id, max_cursor, _sign, dytk)
  req = requests.get(user_url, headers=self.headers)
  while req.status_code != 200:
  req = requests.get(user_url, headers=self.headers)
  html = json.loads(req.text)
  try:
  while html['aweme_list'] == []:
   i = i + 1
   sys.stdout.write('已重新链接' + str(i) + '次 (若超过100次,请ctrl+c强制停止再重来)' + '\r')
   sys.stdout.flush()
   process = Popen(['node', 'fuck-byted-acrawler.js', str(user_id)], stdout=PIPE, stderr=PIPE)
   _sign = process.communicate()[0].decode().strip('\n').strip('\r')
   user_url = user_url_prefix + '/?user_id=%s&max_cursor=%s&count=21&aid=1128&_signature=%s&dytk=%s' % (user_id, max_cursor, _sign, dytk)
   req = requests.get(user_url, headers=self.headers)
   while req.status_code != 200:
   req = requests.get(user_url, headers=self.headers)
   html = json.loads(req.text)
  except:
  pass
  i = 0
  for each in html['aweme_list']:
  try:
   url = 'https://aweme.snssdk.com/aweme/v1/play/?video_id=%s&line=0&ratio=720p&media_type=4&vr_type=0&test_cdn=None&improve_bitrate=0'
   uri = each['video']['play_addr']['uri']
   video_url = url % uri
  except:
   continue
  share_desc = each['share_info']['share_desc']
  if os.name == 'nt':
   for c in r'\/:*?"<>|':
   nickname = nickname.replace(c, '').strip().strip('\.')
   share_desc = share_desc.replace(c, '').strip()
  share_id = each['aweme_id']
  if share_desc in ['抖音-原创音乐短视频社区', 'TikTok', '']:
   video_names.append(share_id + '.mp4')
  else:
   video_names.append(share_id + '-' + share_desc + '.mp4')
  share_urls.append(each['share_info']['share_url'])
  video_urls.append(video_url)
  max_cursor = html['max_cursor']
  has_more = html['has_more']
 return video_names, video_urls, share_urls, nickname
 def get_download_url(self, video_url, watermark_flag):
 """
 获得带水印的视频播放地址
 Parameters:
  video_url:带水印的视频播放地址
 Returns:
  download_url: 带水印的视频下载地址
 """
 # 带水印视频
 if watermark_flag == True:
  download_url = video_url.replace('/play/', '/playwm/')
 # 无水印视频
 else:
  download_url = video_url.replace('/playwm/', '/play/')
 return download_url
 def video_downloader(self, video_url, video_name, watermark_flag=False):
 """
 视频下载
 Parameters:
  video_url: 带水印的视频地址
  video_name: 视频名
  watermark_flag: 是否下载带水印的视频
 Returns:
  无
 """
 size = 0
 video_url = self.get_download_url(video_url, watermark_flag=watermark_flag)
 with closing(requests.get(video_url, headers=self.headers, stream=True)) as response:
  chunk_size = 1024
  content_size = int(response.headers['content-length'])
  if response.status_code == 200:
  sys.stdout.write(' [文件大小]:%0.2f MB\n' % (content_size / chunk_size / 1024))
  with open(video_name, 'wb') as file:
   for data in response.iter_content(chunk_size = chunk_size):
   file.write(data)
   size += len(data)
   file.flush()
   sys.stdout.write(' [下载进度]:%.2f%%' % float(size / content_size * 100) + '\r')
   sys.stdout.flush()
 def run(self):
 """
 运行函数
 Parameters:
  None
 Returns:
  None
 """
 self.hello()
 print('搜索api需要登录,暂时使用UID下载\n分享用户页面,用浏览器打开短链接,原始链接中/share/user/后的数字即是UID')
 user_id = input('请输入ID (例如95006183):')
 user_id = user_id if user_id else '95006183'
 watermark_flag = input('是否下载带水印的视频 (0-否(默认), 1-是):')
 watermark_flag = watermark_flag if watermark_flag!='' else '0'
 watermark_flag = bool(int(watermark_flag))
 type_flag = input('f-收藏的(默认), p-上传的:')
 type_flag = type_flag if type_flag!='' else 'f'
 save_dir = input('保存路径 (例如"E:/Download/", 默认"./Download/"):')
 save_dir = save_dir if save_dir else "./Download/"
 video_names, video_urls, share_urls, nickname = self.get_video_urls(user_id, type_flag)
 nickname_dir = os.path.join(save_dir, nickname)
 if not os.path.exists(save_dir):
  os.makedirs(save_dir)
 if nickname not in os.listdir(save_dir):
  os.mkdir(nickname_dir)
 if type_flag == 'f':
  if 'favorite' not in os.listdir(nickname_dir):
  os.mkdir(os.path.join(nickname_dir, 'favorite'))
 print('视频下载中:共有%d个作品!\n' % len(video_urls))
 for num in range(len(video_urls)):
  print(' 解析第%d个视频链接 [%s] 中,请稍后!\n' % (num + 1, share_urls[num]))
  if '\\' in video_names[num]:
  video_name = video_names[num].replace('\\', '')
  elif '/' in video_names[num]:
  video_name = video_names[num].replace('/', '')
  else:
  video_name = video_names[num]
  video_path = os.path.join(nickname_dir, video_name) if type_flag!='f' else os.path.join(nickname_dir, 'favorite', video_name)
  if os.path.isfile(video_path):
  print('视频已存在')
  else:
  self.video_downloader(video_urls[num], video_path, watermark_flag)
  print('\n')
 print('下载完成!')
 def hello(self):
 """
 打印欢迎界面
 Parameters:
  None
 Returns:
  None
 """
 print('*' * 100)
 print('\t\t\t\t抖音App视频下载小助手')
 print('\t\t作者:Jack Cui、steven7851')
 print('*' * 100)
if __name__ == '__main__':
 douyin = DouYin()
 douyin.run()

总结

以上所述是小编给大家介绍的python3下载抖音视频的完整代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
Python统计列表中的重复项出现的次数的方法
Aug 18 Python
Python中if __name__ == &quot;__main__&quot;详细解释
Oct 21 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
Nov 21 Python
Python时间模块datetime、time、calendar的使用方法
Jan 13 Python
Python面向对象编程之继承与多态详解
Jan 16 Python
Python线性拟合实现函数与用法示例
Dec 13 Python
python使用Plotly绘图工具绘制柱状图
Apr 01 Python
Python实现使用dir获取类的方法列表
Dec 24 Python
python中如何使用insert函数
Jan 09 Python
Python GUI编程学习笔记之tkinter事件绑定操作详解
Mar 30 Python
Python数据库封装实现代码示例解析
Sep 05 Python
python pip如何手动安装二进制包
Sep 30 Python
把JSON数据格式转换为Python的类对象方法详解(两种方法)
Jun 04 #Python
Django集成搜索引擎Elasticserach的方法示例
Jun 04 #Python
python添加菜单图文讲解
Jun 04 #Python
Python3.6+Django2.0以上 xadmin站点的配置和使用教程图解
Jun 04 #Python
Python自动化之数据驱动让你的脚本简洁10倍【推荐】
Jun 04 #Python
pandas DataFrame索引行列的实现
Jun 04 #Python
深入浅析Python中的迭代器
Jun 04 #Python
You might like
php Static关键字实用方法
2010/06/04 PHP
通过php快速统计某个数据库中每张表的数据量
2012/09/04 PHP
探讨Smarty中如何获取数组的长度以及smarty调用php函数的详解
2013/06/20 PHP
wordpress安装过程中遇到中文乱码的处理方法
2015/04/21 PHP
详解WordPress中简码格式标签编写的基本方法
2015/12/22 PHP
php基于自定义函数记录log日志方法
2017/07/21 PHP
TinyMCE 新增本地图片上传功能
2010/11/05 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
仅img元素创建后不添加到文档中会执行onload事件的解决方法
2011/07/31 Javascript
javascript将浮点数转换成整数的三个方法
2014/06/23 Javascript
浅析Javascript中“==”与“===”的区别
2014/12/23 Javascript
javascript强制点击广告的方法
2015/02/06 Javascript
JavaScript中原型和原型链详解
2015/02/11 Javascript
JavaScript使用Prototype实现面向对象的方法
2015/04/14 Javascript
jQuery编写textarea输入字数限制代码
2017/03/23 jQuery
Node.js实现文件上传的示例
2017/06/28 Javascript
MUI实现上拉加载和下拉刷新效果
2017/06/30 Javascript
weui框架实现上传、预览和删除图片功能代码
2017/08/24 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
KnockoutJS数组比较算法实例详解
2019/11/25 Javascript
JavaScript进阶(三)闭包原理与用法详解
2020/05/09 Javascript
Python实现正整数分解质因数操作示例
2018/08/01 Python
浅述python2与python3的简单区别
2018/09/19 Python
使用HTML5拍照示例代码
2013/08/06 HTML / CSS
佳能英国官方网站:Canon UK
2017/08/08 全球购物
蒙蒂塞罗商店:Monticello Shop
2018/11/25 全球购物
美国木工工具和用品商店:Woodcraft
2019/10/30 全球购物
西雅图电动自行车公司:Rad Power Bikes
2020/02/02 全球购物
什么是Connection-oriented Protocol/Connectionless Protocol面向连接的协议/无连接协议
2012/09/06 面试题
求职信模板标准格式范文
2014/02/23 职场文书
机械工程师岗位职责
2014/06/16 职场文书
2015年中学团委工作总结
2015/07/22 职场文书
2016年“5.12”护士节致辞
2015/07/31 职场文书
mysql脏页是什么
2021/07/26 MySQL
Python中的嵌套循环详情
2022/03/23 Python
python+pytest接口自动化之token关联登录的实现
2022/04/06 Python