使用Python半自动下载抖音视频

抖音里面点赞和收藏了很多视频,但是有害怕时间久了,作者将视频删除,因此就想把视频下载下来保存到本地或云盘
但是在抖音里手动下载,操作不是很方便,下载完需要很长时间

  • 但是有些视频因为作者限制不能手动下载

并没有使用Fiddler等抓包工具原因是

  • 还不是很会使用Fiddler工具
  • 抖音做了一些反抓包手段
  • 点赞和收藏列表不像用户主页有分享链接

思路

  • 每个视频都可以复制如下的分享口令,口令中包含是个短链接
1.0 QX:/ 原来一度电可以做那么多事情%萌知计划 %抖来涨知识 @抖音青少年 %物理 @抖音小助手  https://v.douyin.com/eUfrM2s/ 复制此鏈接,打鐦Dou姻搜索,値接观kan视频!
  • 截取短链接到浏览器打开,会重定向到一个如下的播放链接(还不是视频的真实链接)
https://www.iesdouyin.com/share/video/6960618997804977445/?region=CN&mid=6960619064465083144&u_code=10aca5g48&titleType=title&did=MS4wLjABAAAAfyZTr5Gy3ryqXurligO0IZJtULc2TgWWbyRBerWy0Ww&iid=MS4wLjABAAAABiuIM3QYe76mDTtLSVIEbX6oeWoXcr2e48l5skLmHo9P5KXXDUIcbnx5ogZVpQIe&with_sec_did=1&utm_source=copy_link&utm_campaign=client_share&utm_medium=android&app=aweme&scheme_type=1

其实这串链接只需要问号之前就可以了(这一点后面用到)

  • 用浏览器的开发者工具定位到播放位置,可以在源码中看到视频的真实链接


    image.png
  • 根据这个链接下载视频

动手做

截取短链接

用正则表达式截取短链接

def get_douyin_url():
    with open('./douyin_link.txt', 'r', encoding='utf-8') as f:
        kouling = f.read()
        pattern = re.compile(' (https://v.douyin.com/.*?/) ')
        urls = re.findall(pattern, kouling)
    return urls

下载网页源码

获取重定向后的页面链接,并下载页面源码

def get_douyin_page(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57"
    }
    resp = requests.get(url, headers=headers)
    redirect_url = resp.history[0].headers['location']
    
    page_resp = requests.get(redirect_url, headers=headers)
    html = page_resp.content
    with open('./douyin.html', 'w', encoding='utf-8') as f:
        f.write(html)
    return html

打开保存的网页源码,发现并没有视频可播放,用编辑器打开源码,以及使用浏览器的开发者工具,对比浏览器请求的源码和选然后的代码,可以发现视频原链接和视频作者等信息都是浏览器通过JS渲染生成的
分析JS代码是不可能的
使用Selenium+Webdriver打开一个浏览器抓取渲染之后的页面源码
首先想到的是无界面的PhantomJS,因其无界面,运行时占用的内存则很低

def get_douyin_page(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57"
    }
    resp = requests.get(url, headers=headers)
    redirect_url = resp.history[0].headers['location']
    
    driver = webdriver.PhantomJS()
    driver.get(redirect_url)
    sleep(10)
    html = driver.page_source
    with open('./douyin.html', 'w', encoding='utf-8') as f:
        f.write(html)
    return html

发现还是没有抓取到有渲染之后视频原链接的网页源码,不管休眠多长时间都不行
以为此路行不通,不能爬取抖音的时候,发现运行PhantomJS的提示信息


image.png

提示说Selenium对PhantomJS的支持已经被抛弃,请使用无头浏览器
原来Chrome和Firefox也有这种无界面的无头浏览器
从网上抄一个Selenium运行Chrome浏览器的方法

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

url = '...'
chrome_options = Options()
chrome_options.add_argument('--headless')
driver = webdriver(chrome_options=chrome_options)
driver.get(url)
...

由于我从去年把主要使用的浏览器换成了微软最新的Edge浏览器,电脑里没有安装Chrome,也不太喜欢用Firefox
网上说不能用配置Chrome的方法配置Edge,给出的方法是先安装一个Python库msedge-selenium-tools

$ pip install msedge-selenium-tools

在这里的使用,创建一个无头浏览器对象

from time import sleep
from msedge.selenium_tools import EdgeOptions
from msedge.selenium_tools import Edge

def get_douyin_page(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57"
    }
    resp = requests.get(url, headers=headers)
    redirect_url = resp.history[0].headers['location']

    edge_options = EdgeOptions()
    edge_options.use_chromium = True
    edge_options.add_argument('headless')
    driver = Edge(options=edge_options)
    driver.get(redirect_url)
    sleep(10)
    html = driver.page_source
    return driver, html

启动是并没有浏览器的窗口
这里睡眠10秒是为了把所有源码渲染完之后在获取源码,将浏览器driver对象返回的作用后面再说
获取到页面渲染后的源码后就要从源码中提取视频原链接

解析源码 获取视频链接

使用正则表达式提取视频链接

def parse_video_url(html):
    url_pattern = re.compile('<div class="video-player.*?><video.*?src="(.*?)".*?></video>')
    video_url = re.findall(url_pattern, html)[0]
    video_url = video_url.replace('&amp;', '&')
    print('\t', video_url)
    id_pattern = re.compile('id=(.*?)&ratio')
    video_id = re.findall(id_pattern, video_url)[0]
    print('\t', video_id)
    return video_url, video_id

下载源码的时候,Python会自动把链接中的参数连接符(&)替换为对应的字符实体(&amp),先需要还原
将链接中长度为32的参数video_id作为下载视频的文件名

下载视频

def download_video(url, id):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57"
    }
    resp = requests.get(url, headers=headers)
    with open(f'./douyin/{id}.mp4', 'wb') as f:
        f.write(resp.content)

如果在下载网页源码时使用driver.quit()关闭了浏览器,现在下载视频时就会提示ConnectionAbortedError: [WinError 10053] 您的主机中的软件中止了一个已建立的连接,所以需要get_douyin_page()函数中返回浏览器对象driver,在调用download_video()函数下载完视频之后再关闭浏览器

补充

有时候从抖音复制的口令里包含的链接直接就是重定向之后的播放页面链接(域名为www.iesdouyin.com),就需要修改截取短链接的正则表达式匹配模式(https://www.iesdouyin.com/share/video/.*?/)?,在下载网页源码的函数中就不再需要前面寻找重定向链接的部分
这样就与前面使用域名为'v.douyin.com'的短链接的代码不同,难道要使用两套代码吗?
试一下,如果不先寻找重定向链接,而是直接给无头浏览器传原来这种短链接能不能获取有视频原链接的网页源码
试了之后,可行.那么改为两种链接都可用的代码

def get_douyin_url():
    with open('./douyin_link.txt', 'r', encoding='utf-8') as f:
        kouling = f.read()
        pattern = re.compile('https://v.douyin.com/.*?/|https://www.iesdouyin.com/share/video/.*?/')
        urls = re.findall(pattern, kouling)
    return urls


def get_douyin_page(url):
    edge_options = EdgeOptions()
    edge_options.use_chromium = True
    edge_options.add_argument('headless')
    driver = Edge(options=edge_options)
    driver.get(url)
    sleep(10)
    html = driver.page_source
    return driver, html

获取短链接函数返回的是一个链接列表,可使用循环多次下载视频

再补充

熟悉多线程和异步的朋友可以试一下,在评论区补充

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354