作 者:煌金的咸鱼
来 源:咸鱼学Python
广而告之:由于此订阅号换了个皮肤,系统自动取消了读者的公众号置顶。导致用户接受文章不及时。您可以打开订阅号,选择置顶(标星)公众号。重磅干货,第一时间送达!
前言
上周看到一个有趣的项目是使用Python+ADB做一个Python 抖音机器人 Douyin-Bot,自动翻页+颜值识别,自动点赞加关注,效果如下图,可以说是非常秀了。
源码地址:https://github.com/wangshub/Douyin-Bot
而我们今天实现的就是批量下载抖音视频,结合上面的机器人可以说是机器人届的蒂花之秀。
今天我们实现的抖音爬虫主要有下面四点功能:
根据抖音号下载用户发布的全部视频
根据链接自动下载用户点赞的视频
根据链接自动下载某个主题下的全部视频
根据链接自动下载某个音乐下的全部视频下面会先以第二个功能为例编写代码。
废话说多了,先上一波爬取的结果:
下载视频截图
输出日志截图
实战
引入类库
import requests
import json
import datetime
import re
import sys
import os
from urllib.parse import urlencode
from contextlib import closing
from requests.packages import urllib3
import random
本次代码的主要功能模块如下:
这次的项目主要是根据用户分享的链接自动下载,首先我们通过分享得到下面的链接:
# 这是用户主页的分享链接
https://www.douyin.com/share/user/61806758871/?share_type=link&from=singlemessage
# 这是音乐界面的分享链接
https://www.iesdouyin.com/share/music/6562721743650491139?timestamp=1528546868&utm_source=weixin&utm_campaign=client_share&utm_medium=android&app=aweme&iid=33943329942
# 这是主题界面的分享链接
https://www.iesdouyin.com/share/challenge/1602334725005380?timestamp=1528546923&utm_source=weixin&utm_campaign=client_share&utm_medium=android&app=aweme&iid=33943329942
根据上面的链接我们可以得到以下代码,并且获得唯一的ID标识
# 解析文件里面读取出来的链接
def parse_url(urls):
musics_id =
challenges_id =
users_id =
for i in range(len(urls)):
url = urls[i]
if url:
# 分析链接是音乐链接
if re.search('share/music',url):
music_id = re.findall('share/music/(.*)\?', url)
# if len(musics_id):
musics_id.append(music_id[0])
for music in musics_id:
print(music)
if music not in os.listdir:
os.mkdir(music)
download_music_media(music)
# 分析链接是主题链接
if re.search('share/challenge', url):
challenge_id = re.findall('share/challenge/(.*)\?',url)
challenges_id.append(challenge_id[0])
for challenge in challenges_id:
if challenge not in os.listdir:
os.mkdir(challenge)
# print(challenge)
download_challenge_media(challenge)
# 分析链接是用户主页,请求下载的是用户喜欢的视频
if re.search('share/user', url):
user_id = re.findall('share/user/(.*)/\?',url)
users_id.append(user_id[0])
for u_id in users_id:
if u_id not in os.listdir:
os.mkdir(u_id)
# print(challenge)
download_ulike_media(u_id)
我们通过浏览器打开上面的链接可以获得以下的Headers信息:
headers = {
'user-agent':random.choice(hds),
'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',
'cache-control': 'max-age=0'
}
我们以第二个获取点赞视频为例,打开我们分享的链接,将开发者模式调整成手机版,点击「喜欢」可以看到请求的链接,如下图:
查看请求链接
获得请求参数
可以看到请求的参数中有一个很奇怪的参数_signature,且每次请求这个参数都不同,通过查阅gayhub上相关项目资料,发现这个参数是链接中的ID号加密获得,所以接下来可以通过调用加密JS对ID加密,就可以构建一个完整的请求。代码如下:
# 构建请求参数
def download_ulike_media(u_id):
p = os.popen('node fuck-byted-acrawler.js %s' % u_id)
signature = p.readlines[0]
params = {
'user_id': str(u_id),
'count': '21',
'max_cursor': '0',
'aid': '1128',
'_signature': signature
}
可以看到上面调用了node.js来执行加密js,所以我们需要安装NODE.JS。
通过构建请求,我们顺利得到请求的结果,如下图,这个时候我们需要解析请求的数据得到视频的链接。
我们通过查看返回的数据,可以发现正确视频的链接形式如下:
https://www.amemv.com/share/video/xxxxxxxxxxx
在这里我们可以获得视频的id就可以构建完整的视频链接。代码如下:
# 拼接视频信息
def get_ulike_url(max_cursor=None, video_count=0):
video_names =
video_urls =
url = 'https://www.amemv.com/share/video/'
if max_cursor:
params['max_cursor'] = str(max_cursor)
ulike_url = 'https://www.douyin.com/aweme/v1/aweme/favorite/?' + urlencode(params)
# print(ulike_url)
res = requests.get(ulike_url, headers=headers, verify=False)
ulike_ms = json.loads(res.content.decode('utf-8'))
favorite_list = str(ulike_ms['aweme_list'])
v_id = re.findall('https://www.amemv.com/share/video/(.*?)\'',favorite_list)
for l in v_id:
share_desc = l + '.mp4'
s_url = url + l
video_names.append(share_desc)
video_urls.append(s_url)
parse_media_url(video_names, video_urls, u_id)
if ulike_ms.get('has_more') == 1:
return get_ulike_url(ulike_ms.get('max_cursor'), video_count)
video_count = get_ulike_url
if video_count == 0:
print('这个用户没有喜欢的视频')
我们点击我们上面构建的视频链接,看下页面的具体情况是什么样的。
查看网页返回的信息
我们打开上图红框中的链接,可以看到是视频的资源地址。
打开源视频地址
按照上述的思路,我们可以构建以下的代码:
# 下载模块
def _download_video(video_url, path):
video_content = get_video_url(video_url)
# print(video_content)
rec = re.compile(r'class="video-player" src="(.*?)"')
pattern = re.compile(r'playwm')
downloadwm_url = rec.search(video_content).group(1)
# 构建无水印下载链接
download_url = re.sub(pattern, 'play', downloadwm_url)
print('正在下载:',download_url, path)
with closing(requests.get(download_url, headers=headers, stream=True, verify=False)) as response:
chunk_size = 1024
if response.status_code == 200:
with open(path, 'wb') as f:
for data in response.iter_content(chunk_size=chunk_size):
f.write(data)
# flush 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。
f.flush
以上就是下载用户点赞视频的代码,相比于其他功能稍微复杂了点,其他功能通过手机抓包就可以获得请求接口,且没有加密参数。本次的项目代码基本类似,这里就以下载音乐视频的代码为例,讲下抓包部分:
这次使用的抓包工具是Charles,基础的配置可以看下面的文章:
10行代码实现自动参与抽奖助手抽奖
配置好Charles后,打开抖音,通过刷新手机页面,可以看到左边栏的请求链接中有两处链接高亮,Charles截图如下:
Charles截图
点击开响应的数据可以看到每一个链接,我们只要解析每个链接中share_url中包含的videoid,再带入到API中就可以得到真实的视频地址了。
解析图中红框中链接包含的videoid
在测试API时强烈建议可以使用Postman来测试链接的可用性,以减少我们请求的参数数量和测试的复杂度。
测试接口时的部分截图
全部代码较多,就不占用文章篇幅,有需要测试的朋友后台回复「抖音」获取代码文件。「代码测试于2018.6.9」
本文首发自:咸鱼学Python,欢迎点击下方链接关注获取更多干货呦~
推荐阅读
1.5年 阿里 Java 工程师的经验分享
2. 让你重新爱上 Windows 的小众软件
3.深入 Spring Boot 核心注解原理
4.推荐 8 个开源的 Spring Boot 学习资源
本文暂时没有评论,来添加一个吧(●'◡'●)