- 学习python也有三个多月了,学爬虫的时候一直都是跟着老师的思路来敲代码,突然心血来潮想自己找个网站试一试。正好想了解我国主题公园的相关信息,因此就想到了爬一下抖音的视频。
- 接下来就是我下载抖音无水印视频的步骤及源码。
二、抓包与分析声明:
- 文章仅仅是记录自己学习的过程,并无其它目的
- 文中思路与代码仅供参考,欢迎交流或指出错误
- 第一次发文,写得不好的地方大家可以提建议
- 码字不易,希望能得到点赞
爬取的链接地址
第一步:打开网页版抖音,搜索关键词“主题公园”,打开抓包工具查看
- 可以看到,现在抓包工具中暂时没有数据包。
- 视频播放,抓包工具也抓到了相应的视频的数据包,我们点开数据包查看相关信息。
- 数据包中可以看到单个视频的地址,复制地址在浏览器中打开,可以查看视频资源。我们可以通过单次请求下载单个视频。
- 但是我们不只是下载单个视频,而是要批量下载指定关键字的视频。因此我们点开数据包的请求参数,看能不能找到一些规律。
- 以上是另外两个视频数据包的参数。通过观察,不同数据包之间参数只在红色框框的地方发生了变化。有规律吗?显然很难找到规律。
- **所以我们思考:有没有其他数据包,里面包含了所有视频的url地址或参数信息?**说做就做!将单个视频数据包的参数信息作为搜索的关键词,在全局搜索中进行搜索,在多次尝试之后找到了数据包。
- 我们点开搜索到的数据包查看相关信息,数据包参数与数据内容如下:
- 从图中可以看到,这个数据包返回的数据类型是json数据,并且点开可以发现,其中有15个数字,每一个数字中都能找到单个视频的地址。观察数据包中的参数,count字段的数值是15,因此猜想这个字段与数据包中视频地址的个数有关。
- 以上是又抓取到的另外一个数据包。通过对比之前的数据包,可以看到 offset字段的值从0变成了15,而count的值变为了10。并且,通过查看数据包中的数据,发现视频地址只有10个。
- 并且第二个数据包中的一些字段与第一个数据包中的字段也存在差异,如图中红色方框部分。
第五步:向数据包地址发送请求,输出返回的数据,验证猜想因此猜想:count 控制的是每个数据包的视频地址个数,而 offset控制的是页数。即,假如count为10,offset初始值为0,则表示第一个数据包。当offset变为10之后,则表示第二个数据包,类似于翻页的实现。
注意:
发送请求一定要加上请求头,cookie也要加
第一次发送请求时,将参数中的offset设置为0,count设置为10
第二次发送请求时,将参数中的offset设置为10,count设置为10
观察两次请求返回的数据是否不相同
在发送请求时,若没有数据返回,则尝试在传入的params参数中加入search_id字段,这样才能返回数据。
def get_response(url,params,headers):
response = requests.get(url=url,headers=headers,params=params)
print(response.json())
return response
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
'cookie': '', #自己复制cookies
'authority': 'www.douyin.com',
'referer': 'https://www.douyin.com/search/%E4%B8%BB%E9%A2%98%E5%85%AC%E5%9B%AD?source=normal_search&aid=0281649e-2b4e-4120-a848-3f9c41dd85ea&enter_from=discover'
}
params = {
'device_platform': 'webapp',
'aid': '6383',
'channel': 'channel_pc_web',
'search_channel': 'aweme_general',
'sort_type': '0',
'publish_time': '0',
'keyword': '主题公园',
'search_source': 'normal_search',
'query_correct_type': '1',
'is_filter_search': '0',
'from_group_id': '',
'offset': 0, #可以尝试多次,改为10,20,30
'count': '10',
'search_id': '20220518165520010141083048175D5134',
'version_code': '170400',
'version_name': '17.4.0',
'cookie_enabled': 'true',
'screen_width': '1536',
'screen_height': '864',
'browser_language': 'zh-CN',
'browser_platform': 'Win32',
'browser_name': 'Chrome',
'browser_version': '101.0.4951.67',
'browser_online': 'true',
'engine_name': 'Blink',
'engine_version': '101.0.4951.67',
'os_name': 'Windows',
'os_version': '10',
'cpu_core_num': '8',
'device_memory': '8',
'platform': 'PC',
'downlink': '10',
'effective_type': '4g',
'round_trip_time': '50',
'webid': '7098692373315798564',
'msToken': 'cPbFWb9_e7tj6PXp_R3ljiS6JwV4KjxxirXoj8Accs2Ifk46PHY0NPBcdknZVUrhnTsfzBP1aWLB240-YsEge0VGhGHUZK9jxFtHN0FylLESJEh4hV9Jemj0YUlXt5fw',
'X-Bogus': 'DFSzswVYuftANxZ0S3kjyM9WX7J1',
'_signature': '_02B4Z6wo00001S9kn3wAAIDBr2ZlPZsGg3UvZJvAAClgB35DDX-5JqDxVx9Ha30uwbIRtIHb39qgaqdTLNijI2qoXjBPO-QF4OO-gkogTjGtlmzLXqIjoEJP11ZeNB2hVJUhxzsGDnfmla8Jcb',
}
二、解析数据与保存
第一步:解析json数据,获取每一个视频地址与标题
def get_VedioData(response):
vedio_datas=[]
json_data = response.json()
# pprint.pprint(json_data)
dtc_lst = json_data['data']
for dct in dtc_lst:
try:
title = dct['aweme_info']['desc']
video_url = dct['aweme_info']['video']['bit_rate'][0]['play_addr']['url_list'][0]
except:
continue
vedio_data=(video_url,title)
vedio_datas.append(vedio_data)
return vedio_datas
'''此处返回的是一个列表,列表中是由地址和标题组成的元组'''
第二步:向视频地址发送请求获取视频数据
'''向视频地址发送请求,保存视频数据'''
def save_vedio(url, filedir, title):
'''
:filedir:文件路径
:url :视频地址
:title :视频标题
'''
video_byte = requests.get(url=url).content
with open(filedir + title + '.mp4', 'wb') as f:
f.write(video_byte)
print(title+' '+'保存成功')
第三步:定义主函数,控制整个程序的运行
'''主函数:控制程序的运行'''
def main(params,url,headers,filedir):
'''
:params :构造之后的params
:url :搜索页面的url
:filedir:文件目录
'''
response=get_response(url=url,headers=headers,params=params)
vedio_datas=get_VedioData(response=response)
# 多线程,提高视频保存的效率
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor:
for vedio_url,title in vedio_datas:
executor.submit(save_vedio,vedio_url,filedir,title)
第四步:多进程提高程序运行效率
if __name__ == '__main__':
# 多进程,提高解析数据包的效率
with concurrent.futures.ProcessPoolExecutor(max_workers=6) as executor1:
for total in range(0,101,10):
try:
filedir = '主题公园抖音视频\'
url = 'https://www.douyin.com/aweme/v1/web/general/search/single/'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
'cookie': '', #自行复制cookies
'authority': 'www.douyin.com',
'referer': 'https://www.douyin.com/search/%E4%B8%BB%E9%A2%98%E5%85%AC%E5%9B%AD?source=normal_search&aid=0281649e-2b4e-4120-a848-3f9c41dd85ea&enter_from=discover'
}
# params需要的其他参数,由于长度太长笔者在文章中已省略,需自行添加
params = {
'offset': total,
'count': '10',
'search_id': '20220518165520010141083048175D5134',
'_signature': '_02B4Z6wo00001S9kn3wAAIDBr2ZlPZsGg3UvZJvAAClgB35DDX-5JqDxVx9Ha30uwbIRtIHb39qgaqdTLNijI2qoXjBPO-QF4OO-gkogTjGtlmzLXqIjoEJP11ZeNB2hVJUhxzsGDnfmla8Jcb',
}
executor1.submit(main,params,url,headers,filedir)
except:
continue



