Python爬虫:皮皮虾短视频无水印下载(新版)
作者:互联网
本博文所写爬取规则最近更新日期为:2021-2-28
提醒:转载请标明作者和原文链接!!!
CSDN个人主页: 高智商白痴
原文地址: https://blog.csdn.net/qq_44700693/article/details/113826111
导入
小寒暄
不知道现在在看这一小节的朋友看没看见过我之前写的Python爬虫:皮皮虾短视频无水印下载。
在这篇文章中我通过打开分享链接,查找到了网页版的视频无水印请求 API ,不过好景不长,几个月后就失效了。
之前之所以那么做,是因为我发现,当在浏览器上打开视频分享链接后,网页版的视频本身加载的就是无水印的视频,所以当然在网页端解析是最好的,但是现在,网页端的视频自动加载为有水印的视频,原网页端无水印视频接口的视频链接字段也变成了空值。
到目前已经有很多人给我私信说有没有最新的解析方法,之后去研究过网页版的,不过都没有成功,无论是参数的加密,还是请求字段的含义,我都一头雾水。
分析过程
在小寒暄中,我说过,之前之所以选择去解析网页版的接口,是因为网页版的视频本身加载的就是无水印的视频,所以我才选择直接解析网页版的,而现在,无论是手机端的网页版还是电脑端的网页版视频都是加载的带水印的视频,所以,我们这次直接从 APP 入手。
上手提示: 皮皮虾的安卓客户端是进行了证书锁定的。而如何解决这个问题,请看我的宁一篇博文:Fiddler:Fiddler新旧版抓包相关总结。
抓包配置:
Fiddler Everywhere
夜神模拟器(Android 5)
证书锁定(SSL/TLS Pinning)顾名思义,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求时,通过比对内置的证书和服务器端证书的内容,以确定这个连接的合法性。
当一切都准备妥当时,我们就可以开始进行抓包分析了:
在这里,我就不得不提我之前几次尝试解析时踩的大坑了,真的不知道是我的原因,还是这个 API 的迷惑性太强~~
我几乎都是从以下这个 API 入手的:
那是因为我在这个 API 的返回体中找到了如下的信息:
origin_video_download !!!
这不就是网页端的无水印视频链接字段吗~~
随便选择一个链接在浏览器打开:
成…成功了???
就算是成功了,但是这些参数就…先不说请求头的几个字段,光请求体就够我受了。
虽然可以自己靠着经验估摸着去解析,但是…我反正是失败了。
接着后面的几次解析都栽在这里了,虽然有点不甘心,但是确实是这样。
主要代码
而这一次,我发现了一个新的接口:
接着上面抓包的来说,我们在软件打开后加载完成,然后删掉所有的抓包信息,在虚拟机上点击进入某一视频的详情页面:
然后停止抓包。
接着慢慢的找那些有价值的信息:
于是又对这个 API 进行解析:
在这里我写了一个可以快速将字符串转为字典的小脚本:
import re def parse_header(s_header): form = {} s_h = re.findall(r'(.*?):(.*?)\n', s_header) for a in s_h: form[a[0].strip()] = a[1].strip() return form
需要的话可以直接取用。
于是就得到了下面的这一版本的代码:
import requests
api_url = 'https://i-lq.snssdk.com/bds/cell/cell_comment/'
headers = {'Accept-Encoding': 'gzip',
'X-SS-QUERIES': '******',
'X-SS-REQ-TICKET': '1614499328380',
'x-vc-bdturing-sdk-version': '2.0.1',
'passport-sdk-version': '30',
'sdk-version': '2',
'User-Agent': 'ttnet okhttp/3.10.0.2',
'Cookie': '******',
'X-Khronos': '1614499329',
'X-Gorgon': '040400a50005d14c4b04f9fa5ac0c9ec9617070b6fcfe1bff0f2',
'Host': 'i-lq.snssdk.com',
'Connection': 'Keep-Alive'}
param = {
'cell_type': '1',
'cell_id': '6884917158271260935',
'offset': '0',
'api_version': '1',
'iid': '1284657529238599',
'device_id': '1179092996603726',
'ac': 'wifi',
'mac_address': '54%3ABF%3A64%3A48%3A8C%3A87',
'channel': 'baidu',
'aid': '1319',
'app_name': 'super',
'version_code': '331',
'version_name': '3.3.1',
'device_platform': 'android',
'ssmix': 'a',
'device_type': 'LIO-AN00',
'device_brand': 'Android',
'language': 'zh',
'os_api': '22',
'os_version': '5.1.1',
'uuid': '863064547881401',
'openudid': '5c2a72be0ea16ab0',
'manifest_version_code': '331',
'resolution': '900*1600',
'dpi': '320',
'update_version_code': '33150',
'_rticket': '1614499328336',
'cdid': '6e3fcc11-5cc4-494f-acbe-d9887dd59e08',
'app_region': 'CN',
'sys_region': 'CN',
'time_zone': 'Asia%2FShanghai',
'app_language': 'ZH',
'carrier_region': 'CN',
'last_channel': '',
'last_update_version_code': '0',
'ts': '1614499328'
}
def parse_url():
response = requests.get(api_url, headers=headers, params=param)
video = response.json()['data']['cell_comments'][0]['comment_info']['item']['video']
video_name = video['text']
video_url = video['video_high']['url_list'][0]['url']
print("video_name:" + video_name)
print("video_url:" + video_url)
if __name__ == '__main__':
parse_url()
运行结果:
video_name:像极了当年没有手机的自己
video_url:http://v3-ppx.ixigua.com/a7e2629a5d88663e2f4ae8804fb67e01/603b62d7/video/m/220de8d705970384c929ba5f75e150f20b9116625db80000645ef6706767/?a=1319&br=1280&bt=320&cd=0%7C0%7C0&ch=0&cr=0&cs=0&cv=1&dr=6&ds=6&er=&l=202102281630490101351550433E018EB7&lr=&mime_type=video_mp4&pl=0&qs=0&rc=am80ZzNxamQ1eDMzaWYzM0ApPDU0NDdnaGQ8Nzw7ZzdnPGcyay5mZG8yNDNfLS1jMTBzczMzYC5gXmJjYDUyNGI2YjE6Yw%3D%3D&vl=&vr=
经检验,获取到的链接的确是无水印的链接,那么接下来就是分析参数了…
其实也不用怎么分析了~
有很多参数是无效的,依次尝试后得到第二个版本的代码:
import requests
path = "./PPX/"
api_url = 'https://i-lq.snssdk.com/bds/cell/cell_comment/'
headers = {
'User-Agent': 'ttnet okhttp/3.10.0.2',
'Host': 'i-lq.snssdk.com',
'Connection': 'Keep-Alive'
}
param = {
'cell_id': '6884917158271260935',
'aid': '1319',
'app_name': 'super',
}
def parse_url():
response = requests.get(api_url, headers=headers, params=param)
video = response.json()['data']['cell_comments'][0]['comment_info']['item']['video']
video_name = video['text']
video_url = video['video_high']['url_list'][0]['url']
print("video_name:" + video_name)
print("video_url:" + video_url)
if __name__ == '__main__':
parse_url()
居然不到 30 行的代码…
为了更加的健壮,平且能够兼容分享链接,所以又有了以下第三版的代码:
import random
import requests
path = "./PPX/"
class PpxNew:
api_url = 'https://i-lq.snssdk.com/bds/cell/cell_comment/'
headers = {
'User-Agent': 'ttnet okhttp/3.10.0.2',
'Host': 'i-lq.snssdk.com',
'Connection': 'Keep-Alive'
}
def __init__(self, s_url):
if '/item/' in s_url:
self.cell_id = s_url.split('?')[0].split('/')[-1]
elif '/s/' in s_url:
self.rel_url = requests.get(s_url, headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}).url
self.cell_id = self.rel_url.split('?')[0].split('/')[-1]
self.param = {
'cell_id': self.cell_id,
'aid': '1319',
'app_name': 'super',
}
def parse_url(self):
response = requests.get(self.api_url, headers=self.headers, params=self.param)
video = response.json()['data']['cell_comments'][0]['comment_info']['item']['video']
video_name = video['text']
if video_name == '':
video_name = int(random.random() * 2 * 1000)
if len(str(video_name)) > 20:
video_name = video_name[:20]
video_url = video['video_high']['url_list'][0]['url']
with open(path + str(video_name) + ".mp4", 'wb')as fp:
fp.write(requests.get(video_url).content)
print("【皮皮虾】: {}.mp4 无水印视频下载完成!".format(video_name))
if __name__ == '__main__':
s_url = 'https://h5.pipix.com/s/eJXwbxC/'
PpxNew(s_url).parse_url()
标签:__,视频,name,Python,爬虫,cell,皮皮虾,video,url 来源: https://blog.csdn.net/qq_44700693/article/details/113826111