查看原文
其他

抖音小姐姐属于你的四种姿势

Java后端 2020-08-21

The following article is from 咸鱼学Python Author 煌金的咸鱼


作 者:煌金的咸鱼

来 源:咸鱼学Python

广而告之:由于此订阅号换了个皮肤,系统自动取消了读者的公众号置顶。导致用户接受文章不及时。您可以打开订阅号,选择置顶(标星)公众号。重磅干货,第一时间送达!

前言

上周看到一个有趣的项目是使用Python+ADB做一个Python 抖音机器人 Douyin-Bot,自动翻页+颜值识别,自动点赞加关注,效果如下图,可以说是非常秀了。


源码地址:
https://github.com/wangshub/Douyin-Bot

而我们今天实现的就是批量下载抖音视频,结合上面的机器人可以说是机器人届的蒂花之秀。

今天我们实现的抖音爬虫主要有下面四点功能:

  • 根据抖音号下载用户发布的全部视频

  • 根据链接自动下载用户点赞的视频

  • 根据链接自动下载某个主题下的全部视频

  • 根据链接自动下载某个音乐下的全部视频
    下面会先以第二个功能为例编写代码。

废话说多了,先上一波爬取的结果:

下载视频截图


输出日志截图

实战

引入类库

import requestsimport jsonimport datetimeimport reimport sysimport osfrom urllib.parse import urlencodefrom contextlib import closingfrom requests.packages import urllib3import 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 学习资源

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存