Python批量爬取抖音APP無水印視頻

一、前言

好久沒有寫文章了,因為最近一直備受小論文的折磨,今天小論文初稿終于寫差不多了。看著好幾天都沒有更新的網站有些心疼,翻了翻爬蟲代碼存貨,決定把抖音APP視頻批量下載的代碼拿出來水個文章。

二、實戰背景

抖音越來越火,感覺它有毒,越刷越上癮,總感覺下一個視頻一定會更精彩,根本停不下來。想將抖音里喜歡的小哥哥/小姐姐的視頻全部存到電腦硬盤里該如何操作?不想有抖音的視頻水印該如何處理?

**當初寫完代碼的截屏:****

三、實戰

1、帶水印視頻下載

先說說帶水印的視頻如何抓去吧。在定好爬取目標的時候,我們應該知道自己需要那些步驟完成這項任務。比如本文中提到的任務:抖音APP固定用戶的視頻批量下載。

思考過程:

  • 想要批量下載視頻首先要獲得這些視頻的鏈接;

  • 想要獲得這些視頻鏈接可以通過用戶的主頁進行查看,想進用戶主頁,我得知道用戶主頁鏈接;

  • 用戶主頁鏈接可以通過抖音APP的搜索功能獲取,那么搜索功能接口如何獲取?當然是抓包看看嘍!

瞧,這樣思考下來,問題是不是梳理的很清楚?

搜索接口:

那么接下來就是抓包分析了,抓包過程請自行嘗試。步驟是這樣的:

  • 配置好Fiddler,即確定Fiddler可以對手機APP進行抓包;

  • 在手機APP搜索框中輸入用戶信息,點擊搜索;

  • 在Fiddler找到搜索接口;

  • 分析這個接口傳遞參數規則;

  • 寫代碼生成相應查詢接口。

通過分析你會發現,我們通過搜索接口返回的JSON數據可以找到用戶主頁信息,接下里用同樣的方法抓取主頁用戶信息再分析一波,這時候就遇到問題了,你會發現用戶主頁鏈接使用了as和cp參數進行了加密,這該如何是好?比如鏈接如下: https://aweme.snssdk.com/aweme/v1/aweme/post/?user_id=63386731255&max_cursor=0&count=20...&as=a18575a0311bfa0c2d

上述鏈接省略號部分是一些手機信息,這部分不是必須參數,可以省略。user_id是用戶id可以通過上個搜索接口獲取,count是用戶視頻數量,同樣可以通過上個搜索接口獲取。那最后的as和cp參數怎么辦?

我沒有逆向抖音APP,就是小小測試了一下,看看能不能繞過這個加密接口?抖音APP自帶視頻分享功能,分享鏈接格式如下: https://www.douyin.com/share/video/6511132370416962829/?region=CN...share_iid=28037626243

中間參數都不重要,在此省略。www.douyin.com域名下存放的是分享的視頻,那么這個用戶主頁信息是否可以通過這個域名進行訪問呢?小小測試一下你會發現,完全沒有問題! https://www.douyin.com/aweme/v1/aweme/post/?user_id=63386731255&max_cursor=0&count=20

這就是沒有加密的接口,驚不驚喜,意不意外?根據這個用戶主頁接口,我們就可以輕松獲取用戶主頁所有的視頻鏈接了。

2、無水印視頻下載

方法一:

無水印視頻下載很簡單,有一個通用的方法,就是使用去水印平臺即可。

我使用的去水印平臺是:http://douyin.iiilab.com/

在輸入框中輸入視頻鏈接點擊視頻解析,就可以獲得無水印視頻鏈接。

這個網站當初我寫代碼的時候是好使的,當初用這個網站下了一些無水印視頻,不過寫這篇文章的時候發現這個取水印平臺無法正常解析了,等它修復好了再用這個功能吧。

這個平臺不僅包括抖音視頻去水印,還支持火山、快手、陌陌、美拍等無水印視頻。所以做一個這個網站的接口還是很合適的。

簡單測試了一下,這個網站的API是需要付費解析的,如果通過模擬請求的方式有些困難,因此決定上瀏覽器模擬器Splinter。

Splinter是個好東西,跟Selenium使用類似,它的配置可以參考我的早期Selenium文章:http://blog.csdn.net/c406495762/article/details/72331737

Splinter有個很詳細的英文文檔:http://splinter.readthedocs.io/en/latest/

這里使用方法就不累述,不過有一點可以說的是,我們可以配置headless參數,來將Splinter配置為無頭瀏覽器,啥事無頭瀏覽器呢?就是運行Splinter不調出瀏覽器界面,直接在后臺模擬各種請求,很是方便。

這部分的代碼很簡單,無非就是填充元素,確定解析按鈕位置,點擊按鈕,獲取視頻下載鏈接即可。這點小問題,就自行分析吧。

整體代碼:

#?-*-?coding:utf-8?-*-  
from?splinter.driver.webdriver.chrome?import?Options,?Chrome  
from?splinter.browser?import?Browser  
from?contextlib?import?closing  
import?requests,?json,?time,?re,?os,?sys,?time  
from?bs4?import?BeautifulSoup  

class?DouYin(object):  
????def?__init__(self,?width?=?500,?height?=?300):  
????????"""  
????????抖音App視頻下載  
????????"""  
????????#?無頭瀏覽器  
????????chrome_options?=?Options()  
????????chrome_options.add_argument('user-agent="Mozilla/5.0?(Windows?NT?6.1;?WOW64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/63.0.3239.132?Safari/537.36"')  
????????self.driver?=?Browser(driver_name='chrome',?executable_path='D:/chromedriver',?options=chrome_options,?headless=True)  

????def?get_video_urls(self,?user_id):  
????????"""  
????????獲得視頻播放地址  
????????Parameters:  
????????????user_id:查詢的用戶ID  
????????Returns:  
????????????video_names:?視頻名字列表  
????????????video_urls:?視頻鏈接列表  
????????????nickname:?用戶昵稱  
????????"""  
????????video_names?=?[]  
????????video_urls?=?[]  
????????unique_id?=?''  
????????while?unique_id?!=?user_id:  
????????????search_url?=?'https://api.amemv.com/aweme/v1/discover/search/?cursor=0&keyword=%s&count=10&type=1&retry_type=no_retry&iid=17900846586&device_id=34692364855&ac=wifi&channel=xiaomi&aid=1128&app_name=aweme&version_code=162&version_name=1.6.2&device_platform=android&ssmix=a&device_type=MI+5&device_brand=Xiaomi&os_api=24&os_version=7.0&uuid=861945034132187&openudid=dc451556fc0eeadb&manifest_version_code=162&resolution=1080*1920&dpi=480&update_version_code=1622'?%?user_id  
????????????req?=?requests.get(url?=?search_url,?verify?=?False)  
????????????html?=?json.loads(req.text)  
????????????aweme_count?=?html['user_list'][0]['user_info']['aweme_count']  
????????????uid?=?html['user_list'][0]['user_info']['uid']  
????????????nickname?=?html['user_list'][0]['user_info']['nickname']  
????????????unique_id?=?html['user_list'][0]['user_info']['unique_id']  
????????user_url?=?'https://www.douyin.com/aweme/v1/aweme/post/?user_id=%s&max_cursor=0&count=%s'?%?(uid,?aweme_count)  
????????req?=?requests.get(url?=?user_url,?verify?=?False)  
????????html?=?json.loads(req.text)  
????????i?=?1  
????????for?each?in?html['aweme_list']:  
????????????share_desc?=?each['share_info']['share_desc']  
????????????if?'抖音-原創音樂短視頻社區'?==?share_desc:  
????????????????video_names.append(str(i)?+?'.mp4')  
????????????????i?+=?1  
????????????else:  
????????????????video_names.append(share_desc?+?'.mp4')  
????????????video_urls.append(each['share_info']['share_url'])  

????????return?video_names,?video_urls,?nickname  

????def?get_download_url(self,?video_url):  
????????"""  
????????獲得帶水印的視頻播放地址  
????????Parameters:  
????????????video_url:帶水印的視頻播放地址  
????????Returns:  
????????????download_url:?帶水印的視頻下載地址  
????????"""  
????????req?=?requests.get(url?=?video_url,?verify?=?False)  
????????bf?=?BeautifulSoup(req.text,?'lxml')  
????????script?=?bf.find_all('script')[-1]  
????????video_url_js?=?re.findall('var?data?=?\[(.+)\];',?str(script))[0]  
????????video_html?=?json.loads(video_url_js)  
????????download_url?=?video_html['video']['play_addr']['url_list'][0]  
????????return?download_url  

????def?video_downloader(self,?video_url,?video_name,?watermark_flag=False):  
????????"""  
????????視頻下載  
????????Parameters:  
????????????video_url:?帶水印的視頻地址  
????????????video_name:?視頻名  
????????????watermark_flag:?是否下載不帶水印的視頻  
????????Returns:  
????????????無  
????????"""  
????????size?=?0  
????????if?watermark_flag?==?True:  
????????????video_url?=?self.remove_watermark(video_url)  
????????else:  
????????????video_url?=?self.get_download_url(video_url)  
????????with?closing(requests.get(video_url,?stream=True,?verify?=?False))?as?response:  
????????????chunk_size?=?1024  
????????????content_size?=?int(response.headers['content-length'])?  
????????????if?response.status_code?==?200:  
????????????????sys.stdout.write('??[文件大小]:%0.2f?MB\n'?%?(content_size?/?chunk_size?/?1024))  

????????????????with?open(video_name,?"wb")?as?file:??  
????????????????????for?data?in?response.iter_content(chunk_size?=?chunk_size):  
????????????????????????file.write(data)  
????????????????????????size?+=?len(data)  
????????????????????????file.flush()  

????????????????????????sys.stdout.write('??[下載進度]:%.2f%%'?%?float(size?/?content_size?*?100)?+?'\r')  
????????????????????????sys.stdout.flush()  


????def?remove_watermark(self,?video_url):  
????????"""  
????????獲得無水印的視頻播放地址  
????????Parameters:  
????????????video_url:?帶水印的視頻地址  
????????Returns:  
????????????無水印的視頻下載地址  
????????"""  
????????self.driver.visit('http://douyin.iiilab.com/')  
????????self.driver.find_by_tag('input').fill(video_url)  
????????self.driver.find_by_xpath('//button[@class="btn?btn-default"]').click()  
????????html?=?self.driver.find_by_xpath('//div[@class="thumbnail"]/div/p')[0].html  
????????bf?=?BeautifulSoup(html,?'lxml')  
????????return?bf.find('a').get('href')  

????def?run(self):  
????????"""  
????????運行函數  
????????Parameters:  
????????????None  
????????Returns:  
????????????None  
????????"""  
????????self.hello()  
????????user_id?=?input('請輸入ID(例如40103580):')  
????????video_names,?video_urls,?nickname?=?self.get_video_urls(user_id)  
????????if?nickname?not?in?os.listdir():  
????????????os.mkdir(nickname)  
????????print('視頻下載中:共有%d個作品!\n'?%?len(video_urls))  
????????for?num?in?range(len(video_urls)):  
????????????print('??解析第%d個視頻鏈接?[%s]?中,請稍后!\n'?%?(num+1,?video_urls[num]))  
????????????if?'\\'?in?video_names[num]:  
????????????????video_name?=?video_names[num].replace('\\',?'')  
????????????elif?'/'?in?video_names[num]:  
????????????????video_name?=?video_names[num].replace('/',?'')  
????????????else:  
????????????????video_name?=?video_names[num]  
????????????self.video_downloader(video_urls[num],?os.path.join(nickname,?video_name))  
????????????print('\n')  

????????print('下載完成!')  

????def?hello(self):  
????????"""  
????????打印歡迎界面  
????????Parameters:  
????????????None  
????????Returns:  
????????????None  
????????"""  
????????print('*'?*?100)  
????????print('\t\t\t\t抖音App視頻下載小助手')  
????????print('\t\t作者:Jack?Cui')  
????????print('*'?*?100)  


if?__name__?==?'__main__':  
????douyin?=?DouYin()  
????douyin.run()  

方法二:

這個方法是通過網友@羽葵的反饋得知的,對下載鏈接直接修改即可得到無水印下載鏈接。 download_url?=?video_html['video']['play_addr']['url_list'][0].replace('playwm','play')

方法簡單粗暴,很好用。好處就是處理速度飛快,缺點是這種方法通用性不強,不同視頻發布平臺的打碼方法可能有不同,需要自行分析。

作者:JackCui
原文鏈接:http://cuijiahua.com/blog/2018/03/spider-5.html



?------------------------------------------------

原文地址:https://mp.weixin.qq.com/s/RFZywRAWcu4BS2ukrVKCSA

轉載請標明來之:阿貓學編程
更多教程:阿貓學編程-python基礎教程

所有評論

如果對文章有異議,請加qq:1752338621