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

640?wx_fmt=png

作 者:煌金的咸鱼

来 源:咸鱼学Python

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

前言

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

640?wx_fmt=gif

源码地址:

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

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

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

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

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

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

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

640?wx_fmt=png

下载视频截图

640?wx_fmt=png

输出日志截图

实战

引入类库

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

本次代码的主要功能模块如下:

640?wx_fmt=png

这次的项目主要是根据用户分享的链接自动下载,首先我们通过分享得到下面的链接:

# 这是用户主页的分享链接	
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'	
}

我们以第二个获取点赞视频为例,打开我们分享的链接,将开发者模式调整成手机版,点击「喜欢」可以看到请求的链接,如下图:

640?wx_fmt=png

查看请求链接

640?wx_fmt=png

获得请求参数

可以看到请求的参数中有一个很奇怪的参数_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。

640?wx_fmt=png

我们通过查看返回的数据,可以发现正确视频的链接形式如下:

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('这个用户没有喜欢的视频')

我们点击我们上面构建的视频链接,看下页面的具体情况是什么样的。

640?wx_fmt=png

查看网页返回的信息

我们打开上图红框中的链接,可以看到是视频的资源地址。

640?wx_fmt=png

打开源视频地址

按照上述的思路,我们可以构建以下的代码:

# 下载模块	
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()

以上就是下载用户点赞视频的代码,相比于其他功能稍微复杂了点,其他功能通过手机抓包就可以获得请求接口,且没有加密参数。本次的项目代码基本类似,这里就以下载音乐视频的代码为例,讲下抓包部分:10行代码实现自动参与抽奖助手抽奖配置好Charles后,打开抖音,通过刷新手机页面,可以看到左边栏的请求链接中有两处链接高亮,Charles截图如下:

640?wx_fmt=png

Charles截图

点击开响应的数据可以看到每一个链接,我们只要解析每个链接中share_url中包含的videoid,再带入到API中就可以得到真实的视频地址了。

640?wx_fmt=png

解析图中红框中链接包含的videoid

在测试API时强烈建议可以使用Postman来测试链接的可用性,以减少我们请求的参数数量和测试的复杂度。

640?wx_fmt=png

测试接口时的部分截图

全部代码较多,就不占用文章篇幅,有需要测试的朋友后台回复「抖音」获取代码文件。「代码测试于2018.6.9」

本文首发自:咸鱼学Python,欢迎点击下方链接关注获取更多干货呦~

1. 

2. 

3. 

4. 

640?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值