前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >120行代码下载抖音无水印视频「Python语言」

120行代码下载抖音无水印视频「Python语言」

作者头像
申霖
发布2020-02-14 18:03:33
3.9K2
发布2020-02-14 18:03:33
举报
文章被收录于专栏:小白程序猿小白程序猿

过年在家没什么事情做,一直在刷抖音,就想写个代码,试着去下载抖音的原视频文件,昨天写了一会,在下载上面出现了问题,没有成功的下载视频文件。今天上午又研究了一下。成功实现了下载抖音无水印视频文件。整体代码120行。下面一起来看一下吧!

一、需要手机上下载抖音

打开抖音随便找一个视频,点击分享按钮,将其分享到微信,我们要获取到分享的内容,如图一。

1.png
1.png

二、获取抖音短链接

将图一中的链接地址提取出来,这里就手动提取一下吧,不用代码执行了。留着备用,可以保存到文本文件中,方便后续的粘贴。

三、实现过程

通过分享的内容,提取出抖音的短链接,我们在浏览器上实际打开这个链接,会看到这是一个视频的播放页面,这个页面的视频文件也是可以进行下载的,但是这样的下载是存在水印的,来分析一下源代码,发现有一段Javascript代码中,出现了视频的播放路径,如图二。

2.png
2.png

将参数地址在浏览器上进行打开,发现是视频的播放地址,我们继而来观察一下这个播放地址,同时我们在下载的时候可以下载到无水印的视频文件,那么服务器上面肯定存在无水印的视频源文件,水印一词:watermark,猜想一下,将链接中的playwm是不是播放地址加水印的呢?那么我们就将wm进行去掉,发现地址仍可以播放,但是必须是在移动设备端,当我们在pc设备端时就是白屏的情况。拿到了视频的存储位置,接下来就是对文件进行下载了。需要模拟移动设备请求视频地址,然后对文件进行下载。

四、代码(详细代码见评论,已上传至百度网盘分享)

代码语言:javascript
复制
# -*- coding: utf-8 -*-
# 下载抖音无水印视频
from bs4 import BeautifulSoup
import requests
import re
import os
import time


def main():
    print("抖音短视频,无水印素材下载")
    url = input("请输入链接地址:")
    article = get_code(url)
    pattern = re.compile('s_vid=([a-z0-9]+)&line=0')
    script = article.find("script", text=pattern)
    s_vid = pattern.search(script.text).group(1)
    # 拼合链接
    video_url = 'https://aweme.snssdk.com/aweme/v1/play/?s_vid=%s&line=0' % s_vid
    res_url = get_redirect_url(video_url)
    # 视频名称
    video_name_data = get_true_name(url)
    # 进行下载
    print("正在下载中~~~~")
    do_load_media(res_url, './video/%s.mp4' % video_name_data)
    print("运行完成")


# 获取源代码
def get_code(url):
    if not url:
        url = input("请输入链接地址:")
    # 获取响应码
    res = requests.get(url)
    code = res.status_code
    if code != 200:
        print('无法响应')
    # 获取页面代码
    headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
        "Cookie": "anonymid=j3jxk555-nrn0wh; _r01_=1; _ga=GA1.2.1274811859.1497951251; _de=BF09EE3A28DED52E6B65F6A4705D973F1383380866D39FF5; ln_uact=mr_mao_hacker@163.com; depovince=BJ; jebecookies=54f5d0fd-9299-4bb4-801c-eefa4fd3012b|||||; JSESSIONID=abcI6TfWH4N4t_aWJnvdw; ick_login=4be198ce-1f9c-4eab-971d-48abfda70a50; p=0cbee3304bce1ede82a56e901916d0949; first_login_flag=1; ln_hurl=http://hdn.xnimg.cn/photos/hdn421/20171230/1635/main_JQzq_ae7b0000a8791986.jpg; t=79bdd322e760beae79c0b511b8c92a6b9; societyguester=79bdd322e760beae79c0b511b8c92a6b9; id=327550029; xnsid=2ac9a5d8; loginfrom=syshome; ch_id=10016; wp_fold=0"
    }
    content = requests.get(url, headers=headers, timeout=3000)
    # 设置编码格式
    content.coding = 'UTF-8'
    # 以文本形式获取源码
    content_text = content.text
    # 利用解析器进行解析操作
    article = BeautifulSoup(content_text, "html.parser")
    return article


# 下载视频
def do_load_media(url, save_path):
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/71.0.3578.98 Safari/537.36'}
        pre_content_length = 0
        # 循环接收视频数据
        while True:
            # 若文件已经存在,则断点续传,设置接收来需接收数据的位置
            if os.path.exists(save_path):
                headers['Range'] = 'bytes=%d-' % os.path.getsize(save_path)
            res = requests.get(url, stream=True, headers=headers)

            content_length = int(res.headers['content-length'])
            # 若当前报文长度小于前次报文长度,或者已接收文件等于当前报文长度,则可以认为视频接收完成
            if content_length < pre_content_length or (
                    os.path.exists(save_path) and os.path.getsize(save_path) == content_length) or content_length == 0:
                break
            pre_content_length = content_length

            # 写入收到的视频数据
            with open(save_path, 'ab') as file:
                file.write(res.content)
                file.flush()
                print('下载成功:文件大小 : %s  总下载大小:%s' % (StrOfSize(os.path.getsize(save_path)), StrOfSize(content_length)))
    except Exception as e:
        print(e)


# 文件大小转化
def StrOfSize(size):
    '''
    auth: wangshengke@kedacom.com ;科达柯大侠
    递归实现,精确为最大单位值 + 小数点后三位
    '''

    def strofsize(integer, remainder, level):
        if integer >= 1024:
            remainder = integer % 1024
            integer //= 1024
            level += 1
            return strofsize(integer, remainder, level)
        else:
            return integer, remainder, level

    units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
    integer, remainder, level = strofsize(size, 0, 0)
    if level + 1 > len(units):
        level = -1
    return ('{}.{:>03d} {}'.format(integer, remainder, units[level]))


# 重定向的链接,模拟安卓请求地址
def get_redirect_url(url):
    header = {
        'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
        'Upgrade-Insecure-Requests': '1',
    }
    data = requests.get(headers=header, url=url, timeout=5)
    return data.url


# 获取名称
def get_true_name(url):
    true_url = get_redirect_url(url)
    article = get_code(true_url)
    name = article.find(class_="desc")
    if name:
        return name.string
    else:
        return time.time()


if __name__ == '__main__':
    main()

五、代码解读

代码中的视频下载方法、文件大小转换方法均来源于网络,其实整个过程并不复杂,主要是分析抖音播放的代码和请求,通过模拟方式分步骤进行获取参数,最终获取到无水印视频的播放地址,这个地址可以通过其他的下载工具进行下载,抖音视频文件时间在60s之内,文件也不是很大,默认代码下载的方式也不会太耗费时间。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档