Python爬虫:短视频平台无水印下载(上) 2022-11-29 03:05 332阅读 0赞 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center] 本博客所写爬取规则最近更新日期为:2020/12/11 `新增:西瓜视频` `皮皮虾的解析规则已经失效,新版规则已更新` **提醒:转载请标明作者和原文链接!!!** > **CSDN个人主页:** [高智商白痴][Link 1] > **原文地址:** [https://blog.csdn.net/qq\_44700693/article/details/108089085][https_blog.csdn.net_qq_44700693_article_details_108089085] ### 日常跳转: ### * * 导入: * * 分平台解释: * * 皮皮虾 * 皮皮搞笑 * * * 抓包分析 * 源码及结果 * 抖音 / 抖音极速版 * * * 抓包分析 * 代码及结果 * 小优化: * 腾讯微视 * * * 抓包及分析 * 代码及结果 * 开眼 Eyepetizer * * * 抓包分析 * 代码及结果 * 快手/快手极速版 * * 单个视频下载 * * 抓包分析 * 代码及结果 * 用户视频下载 * * 抓包分析 * 代码及结果 * 抖音火山版/火山极速版 * * 单个视频下载 * * 代码及结果: * 用户视频下载 * * 抓包分析 * 代码及结果: * 最右 * * 单个视频下载 * * 代码及结果 * 话题视频下载 * * 代码及分析 * 代码及结果: * 小优化: * VUE * * 单个视频下载 * * 抓包与分析 * 代码及结果 * 话题视频下载 * * 抓包与分析 * 代码及结果: * 看看视频 * * * 抓包与分析 * 代码及结果 * 小优化 * 哔哩哔哩 * AcFun * ZzzFun * 西瓜视频 * * * 抓包分析 * 类源码 * 结果 * 编写中。。。 ## 导入: ## 虽然目前有些软件还没适配,但是,我发了 **Blink** 后有一写人留言或者私信找我要源码,不过我还在增加适配的软件,所以还没有时间写这篇博客,今天呢,就先把我目前适配了的代码拿出来,后续还会继续适配的! ### 分平台解释: ### #### 皮皮虾 #### 皮皮虾的话,我之前就已经写过一个单独的博客了,这里就不再赘述:—> [Python爬虫:皮皮虾短视频无水印下载][Python] -------------------- `该解析规则已失效,仅供学习使用,新版地址:`[Python爬虫:皮皮虾短视频无水印下载(新版)][Python 1] -------------------- #### 皮皮搞笑 #### 皮皮搞笑与皮皮虾很类似,也是先获取分享链接,在电脑端进行分析: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center] ###### 抓包分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 1] 我们可以很容易的在抓包资源 **HXR** 中找到某一固定的链接: ***https://h5.ippzone.com/ppapi/share/fetch\_content*** ,在该链接中的 **video** 字段可以看到有两个链接,分别打开尝试一下可以发现: 后缀含有 **wm** 的链接是含有水印的视频,另一个则是我们的目标链接了,但是我们又发现,在 **video** 字段下,还有一个全是数字的字符串,我们在当前 **json** 文件中搜索可以发现: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 2] 在上一个标签 **img** 下,有一个 **id** 字段,和字符串标签一样。 知道了视频链接的存放位置和获取方式,接下来开始分析请求: ![在这里插入图片描述][20200818100639452.png_pic_center] ![在这里插入图片描述][20200818100716137.png_pic_center] 在尝试过几次抓包后发现,**请求 URL** 始终都没有变化,只是下面的 **请求负载** 有所变化,第三个参数 **post** 默认不变就好,至于前两个参数,都在分享链接跳转的链接中: > **https://h5.ippzone.com/pp/post/350259149175?zy\_to=copy\_link&share\_count=1&m=0cd13da8548a1bc85813d8c60d331e22&app=&type=post&did=d2bddf23159ae495&mid=1270840711117&pid=350259149175** ###### 源码及结果 ###### 一切准备工作做好后,开始编写代码: """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ class PPGX(): # 皮皮搞笑 def __init__(self, url): s_url = url self.headers = { 'Host': 'share.ippzone.com', 'Origin': 'http://share.ippzone.com', 'Referer': s_url, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52' } self.JSON = { "pid": int(str(s_url).split('=')[-1]), "mid": int(str(s_url).split('&')[-2].split('=')[-1]), "type": "post" } def ppgx_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ URL = 'http://share.ippzone.com/ppapi/share/fetch_content' r = requests.post(URL, proxies=proxy, headers=self.headers, json=self.JSON) video_name = r.json()['data']['post']['content'].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = r.json()['data']['post']['videos'][str(r.json()['data']['post']['imgs'][0]['id'])]['url'] video = requests.get(video_url, proxies=proxy).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【皮皮搞笑】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 1] -------------------- #### 抖音 / 抖音极速版 #### 接下来以 **抖音** 为例(抖音极速版的解析方式和抖音相同): 同样的思路,拿到分享链接到电脑浏览器中抓包分析: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 3] 拿到如下信息: **摆摊的第二天……\#架子鼓演奏 \#架子鼓 \#乐器 \#听心 https://v.douyin.com/JMKHkqt/ 复制此链接,打开【抖音短视频】,直接观看视频!** 所以为了方便,使用正则表达式来提取该内容中的链接: `url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接` ###### 抓包分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 2] 我们可以在抓包资源 **HXR** 中找到某一请求,在该 **json** 文件中 **play\_addr** 字段下可以找到视频链接,用浏览器打开: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 3] 该链接跳转到了视频是没错,不过直接跳转到了又水印的链接上,这就有点卡住了。 不过,按照皮皮搞笑的链接区分来看, **wm** 是含有水印的视频的话。 > https://aweme.snssdk.com/aweme/v1/playwm/?video\_id=v0200f750000bsegsdpphaglno4mqd8g&ratio=720p&line=0 当我们删掉链接中的 **wm** 字段后: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 4] **没有加载???????** 而且我们可以发现链接根本都还没有跳转。 **但是:** 当我们把设备切换为手机时: 链接跳转到了无水印的视频链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 5] ###### 代码及结果 ###### 当一切都分析完后,开始编写代码: **注意:** 当我们去掉 **wm** 字段后,下载视频时,需要带上模拟手机端的请求头! class DY(): # 抖音 headers = { # 模拟手机端 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 def dy_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ rel_url = str(requests.get(self.url, proxies=proxy, headers=self.headers).url) if 'video' == rel_url.split('/')[4]: URL = 'https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=' + rel_url.split('/')[5] + '&dytk=' r = requests.get(URL, proxies=proxy, headers=self.headers) video_url = r.json()['item_list'][0]['video']['play_addr']['url_list'][0].replace('/playwm/', '/play/') video_name = r.json()['item_list'][0]['share_info']['share_title'].split('#')[0].split('@')[0].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【抖音短视频】: {}.mp4 无水印视频下载完成!".format(video_name))".format(video_name)) 结果:由于抖音和抖音极速版的分享内容是一样的,无法分辨哪个平台,所以统一输出。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 6] **但是:** 我发现抖音没事就爱搞幺蛾子,有时分享链接是上文所示: 有时又是一段原链接…所以我,做了一点小小的优化: ###### 小优化: ###### if 'www.iesdouyin.com' in self.s_url: print("【抖音短视频】: {}.mp4 无水印视频下载完成!".format(video_name)) if 'v.douyin.com' in self.s_url: print("【抖音短视频/抖音极速版】: {}.mp4 无水印视频下载完成!".format(video_name)) -------------------- #### 腾讯微视 #### 套路依旧,获取分享链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 7] 拿到链接: > 上不上班无所谓,主要是想蹦迪https://h5.weishi.qq.com/weishi/feed/6XSB277Nr1K5nIKb6/wsfeed?wxplay=1&id=6XSB277Nr1K5nIKb6&spid=8813798054214369280&qua=v1\_and\_weishi\_8.0.6\_588\_312028000\_d&chid=100081014&pkg=3670&attach=cp\_reserves3\_1000370011 ###### 抓包及分析 ###### **注意:** 这里是一个写爬虫的常用思路:将设备切换为手机,因为相对于电脑端,手机端的健壮性没有电脑端好,所以很多东西都可以通过这种方式来抓取,就如这个例子: > **未切换:** > ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 8] > **已切换:** > ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 9] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 10] 依次检查请求后发现:链接也就摆放在 **json** 数据中。 那么,接下来直接分析请求: ![在这里插入图片描述][20200818114144922.png_pic_center] ![在这里插入图片描述][20200818114211111.png_pic_center] 对于 **请求负载** 中的参数,我们可以直接在请求链接中截取: > https://h5.weishi.qq.com/weishi/feed/6XSB277Nr1K5nIKb6/wsfeed?wxplay=1&id=6XSB277Nr1K5nIKb6&spid=8813798054214369280&qua=v1\_and\_weishi\_8.0.6\_588\_312028000\_d&chid=100081014&pkg=3670&attach=cp\_reserves3\_1000370011 其他的参数默认就好,而至于请求链接,同一个视频刷新几次,参数 **t** 就有多少个值: > https://h5.weishi.qq.com/webapp/json/weishi/WSH5GetPlayPage?t=0.764612279656077&g\_tk= > https://h5.weishi.qq.com/webapp/json/weishi/WSH5GetPlayPage?t=0.3168301677339891&g\_tk= > https://h5.weishi.qq.com/webapp/json/weishi/WSH5GetPlayPage?t=0.8888910469548954&g\_tk= > … 而且,有时候长度都不一样,这就把我吓到了!什么加密?这么复杂! 既然同一个视频每次刷新都不一样,是不是跟时间戳有关系???但是这明显不是啊! 正在我为这个参数发愁时,我也不知道我当时是怎么想的,无聊,随机修改了参数 **t** 的几个数字发现,仍然能够获取到视频!!!!!!! 然后我发现:所有的数全是在 **0—1** 之间变化,我用Python的 **random** 产生了一组随机数来看: import random print(random.random()) # 结果: # 0.5890812460827893 我都惊呆了!!就是这种数据啊!我用这个随机数去请求时,结果居然是可行的,这…![在这里插入图片描述][20200818122019841.gif_pic_center] 居然误打误撞的给破解了… ###### 代码及结果 ###### class TXWS(): # 腾讯微视 headers = { # 模拟手机端 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 self.data = { 'datalvl': "all", 'feedid': str(self.url).split('/')[5], 'recommendtype': '0', '_weishi_mapExt': '{}' } def txws_download(self): # 参数 t 为随机数 """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ url = 'https://h5.weishi.qq.com/webapp/json/weishi/WSH5GetPlayPage?t={}&g_tk='.format(random.random()) r = requests.post(url, proxies=proxy, headers=self.headers, data=self.data) video_name = r.json()['data']['feeds'][0]['feed_desc'].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = r.json()['data']['feeds'][0]['video_url'] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【腾讯微视】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 11] -------------------- #### 开眼 Eyepetizer #### 虽然 **开眼** 下载的视频,并没有水印,但是下载好的视频只能在软件内观看,但是我还是想让它下载到它该下载的地址: 套路,套路,还是套路: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 12] ###### 抓包分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 13] 还是很简单的,没什么反爬机制,很容易就会找到了视频的下载地址,接下来直接分析请求: ![在这里插入图片描述][20200818163856658.png_pic_center] 请求链接中只有几个数字需要解析,但是我们发现,它就出现在分享链接中: > https://www.eyepetizer.net/detail.html?vid=208234&utm\_campaign=routine&utm\_medium=share&utm\_source=others&uid=0&resourceType=video&udid=c65aab71b05749d584eac4ee7944bb6274e17596&vc=6030061&vn=6.3.6&size=1080X2070&deviceModel=9&first\_channel=xiaomi&last\_channel=xiaomi&system\_version\_code=27 ###### 代码及结果 ###### class KY_Eyepetizer(): # 开眼 def __init__(self, url): self.vid = str(url).split('=')[1].split('&')[0] self.headers = { 'origin': 'https://www.eyepetizer.net', 'referer': url, 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.58' } def ky_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ url = 'https://baobab.kaiyanapp.com/api/v1/video/{}?f=web'.format(self.vid) r = requests.get(url, proxies=proxy, headers=self.headers) video_name = r.json()['title'].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = r.json()['playUrl'] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【开眼 Eyepetizer】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 14] -------------------- #### 快手/快手极速版 #### ##### 单个视频下载 ##### 我们还是以快手为例(快手极速版的解析规则和快手一样): 依旧按照套路来,不过因为快手的限制,必须登录才能分享: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 15] ###### 抓包分析 ###### 按照以前的套路,将链接粘贴到浏览器,**F12** 抓包,结果并没有获取到任何与当前视频链接相关的信息,既然不在 **json** 文件中,难道在网页源码中???去挨个儿查看后,也不是,这该怎么爬取呢?? 别忘了我前面提到的方法:更改设备。 当我把设备换成手机端后,**json** 数据中也还是没有相关数据,不过!!我在网页源码中找到了我们想要的链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 16] 到这里我们也已经找到了链接存放的地址,接下来则是,如何在这么多的字符里将链接提取出来呢??? **答案是:** 使用正则表达式 。 ###### 代码及结果 ###### class KS(): # 快手 def __init__(self, s_url): self.s_url=s_url.replace('\n','') self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 self.headers = { 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def ks_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ html = requests.get(self.url, headers=self.headers).text video_name = re.findall('name":"(.*?)"', html)[0].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = re.findall('srcNoMark":"(.*?)"', html)[0] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) if '【快手App】' in self.s_url: print("【快手】: {}.mp4 无水印视频下载完成!".format(video_name)) elif '【快手极速版App】' in self.s_url: print("【快手极速版】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 17] -------------------- ##### 用户视频下载 ##### 同样的我们拿到用户首页的分享地址: > 看了这么多快手,还是「贝贝兔很」最好玩了! https://v.kuaishou.com/69cjtE 复制此链接,打开【快手】直接观看! ###### 抓包分析 ###### 还是一贯的套路,更改设备,模拟手机向下刷新发现: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 18] 在新加载出的 **json** 文件中,含有两个重要信息: * **feeds** :包含第19条到37条的视频信息(不是链接,而是一个中亚参数,我后面会提到怎么使用)。 * **pcursor** :请求某一部分视频的**重要参数**。 既然包含了第19条到37条的视频,那么第1到第18条的视频信息在哪里呢? 根据前面的教训,我直接查看了**切换到移动设备**时的源码发现: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 19] 这里确实是有18条数据,而且每一个链接直接导向了该视频的首页,那么**解析方式就和单个视频的下载方式一样了!** 对于这18条数据,我们同样可以用正则表达式直接提取,但是后面的几十条数据就需要我们来进行解析了。 我们从新加载的 **json** 文件中可以看到,这里面包含了很多信息,但是却没有视频的链接,但是,既然刷新又必须加载它,说明肯定有什么重要的东西: 后来我发现正则表达式提取出的链接都有像是之处,所以我拿出了几个用正则表达式提取出的链接。(默认前缀) > **/fw/photo/3x3m9e644ep95qg?cc=share\_copylink&fid=574031739&shareId=227013708994&shareToken=X8rcLJByeLfC10c\_A&appType=21&kpn=KUAISHOU** > **/fw/photo/3xggwttf4kquza9?cc=share\_copylink&fid=574031739&shareId=227013708994&shareToken=X8rcLJByeLfC10c\_A&appType=21&kpn=KUAISHOU** > … 我发现对于同一个用户,所有视频的基本形式除了黄色部分不一样以外,其余的都是固定的!这不就是一个参数的问题嘛, **json** 文件中那么多的数据,不信找不到:我一一尝试后终于找到了那个参数: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 20] 既然我们已经知道如何拼接每个视频的链接,那么,最主要的就是如何获取那个视频的关键参数。 我前面已经说了,在 **json** 文件中的 **pcursor** 字段很是重要! ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 21] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 22] 我尝试多次后终于发现发现:前一个 **post** 请求所返回数据中的 **pcursor** 字段的值,就是**下一次请求所需要的参数**!而两次请求中,视频的顺序刚好和用户的一样,所以如何请求后续的视频信息,我们已经知道方法了,不过,第一次的请求的参数是怎么来的呢?? ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 23] 解决: 在编写代码时,我给第一次 **post** 请求的参数 **pcursor** 赋了个**空值**,也是能够请求成功的! 而请求结束的标志就是:**pcursor** 字段的值等于 **no\_more**: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 24] ###### 代码及结果 ###### class KS(): # 快手 def __init__(self, s_url): self.s_url=s_url.replace('\n','') self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 self.headers = { 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } self.video_list = [] self.rel_url = requests.get(self.url, proxies=proxy, headers=self.headers) # 真实网址 def ks_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ if 'user' != self.rel_url.url.split('/')[4]: self.ks_download_video() if 'user' == self.rel_url.url.split('/')[4]: self.ks_download_user() def ks_download_video(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ video_name = re.findall('name":"(.*?)"', self.rel_url.text)[0].replace(' ', '') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = re.findall('srcNoMark":"(.*?)"', self.rel_url.text)[0] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) if '【快手App】' in self.s_url: print("【快手】: {}.mp4 无水印视频下载完成!".format(video_name)) elif '【快手极速版App】' in self.s_url: print("【快手极速版】: {}.mp4 无水印视频下载完成!".format(video_name)) def ks_download_user(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ global user_name headers = { 'Cookie': '粘贴自己的Cookie信息', 'Origin': 'https://c.kuaishou.com', 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.125' } rel_url = requests.get(self.url, proxies=proxy, headers=headers) # 真实网址 user_name = re.findall('<div class="name">(.*?)</div>', rel_url.text)[-1] if os.path.exists(path + user_name + '/'): pass else: os.makedirs(path + user_name + '/') videos = re.findall('<a href="(.*?)" role="ev" data-lazy=', rel_url.text) for video1 in videos: self.video_list.append('https://c.kuaishou.com' + video1) pcursor = '' url = 'https://c.kuaishou.com/rest/kd/feed/profile' flag = 1 while flag: data = { "eid": str(rel_url.url).split('/')[-1].split('?')[0], "count": 18, "pcursor": pcursor} r = requests.post(url, proxies=proxy, headers=headers, json=data) for video2 in tqdm(r.json()['feeds'], desc='正在准备视频链接: '): photoId = video2['share_info'].split('=')[-1] temp_last = '?' + self.video_list[0].split('?')[-1] self.video_list.append('https://c.kuaishou.com/fw/photo/' + photoId + temp_last) pcursor = r.json()['pcursor'] if r.json()['pcursor'] == "no_more": flag = 0 print('用户 {} 共 {} 个视频!'.format(user_name,len(self.video_list))) for video_url in self.video_list: html = requests.get(video_url, headers={ 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X)'}) # 真实网址 print(html.text) video_name = int(random.random() * 2 * 1000) video_url = re.findall('srcNoMark":"(.*?)"', html.text)[0] video = requests.get(video_url, proxies=proxy, headers=headers).content with open(path + user_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【快手】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 25] -------------------- #### 抖音火山版/火山极速版 #### ##### 单个视频下载 ##### 对于这两个软件的解析,其实我是偷懒了,嘿嘿嘿,我翻看以前别人的博客,细细研究后发现了一个快手视频解析的接口: 其实很抱歉我忘记了我在哪个地方看到的那片文章,通过那篇文章,我们可以获取到原火山小视频的视频加载**api** : > https://api-hl.huoshan.com/hotsoon/item/video/\_source/?item\_id=6859730122820291840 原火山小视频无水印接口 > https://api.huoshan.com/hotsoon/item/video/\_reflow/?item\_id=6859730122820291840 抖音火山版水印接口 > https://api.huoshan.com/hotsoon/item/video/\_source/?item\_id=6859730122820291840 抖音火山版无水印接口 现在,已经知道视频加载的 **api** 后,就只需获取视频的 **item\_id** 参数了。这个参数在跳转链接中就可以找到。 ###### 代码及结果: ###### 所以我直接写出来解析代码: class DY_HSB(): headers = { # 模拟手机 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.s_url=s_url self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 def dyhsb_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ rel_url = str(requests.get(self.url, proxies=proxy, headers=self.headers).url) video_name = int(random.random() * 2 * 1000) video_url = 'https://api.huoshan.com/hotsoon/item/video/_source/?item_id=' + \ rel_url.split('=')[1].split('&')[0] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) if '【抖音火山版】' in self.s_url: print("【抖音火山版】: {}.mp4 无水印视频下载完成!".format(video_name)) elif '【火山极速版】' in self.s_url: print("【火山极速版】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果:因为这个 **api** 无法获取其余信息,所以就以随机数来命名。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 26] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 27] ##### 用户视频下载 ##### 我们还是拿到用户首页的分享链接: > 「天使航拍」也在抖音火山版,快来看 TA 的精彩作品吧!「天使航拍」上传了 173 个视频作品,一起来围观>>https://share.huoshan.com/hotsoon/s/FJ0C7M5rWa8/ 复制此链接,打开【抖音火山版】,直接找到TA~ ###### 抓包分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 28] 我们可以很快地找到一个用户视频的请求接口,然后拿到视频的 **item\_id** 参数。但是!这个接口好像**有参数去限制请求视频的数量**,目前我只是试了一下修改请求参数,不过也只能最多爬取该用户40—50 个视频,如果以后有时间,我再去研究一下。 虽然请求参数较多,但是经过我的尝试,只有两个参数是必须的: * **encrypted\_id** : 在请求跳转链接中以 **to\_user\_id** 的参数存在。 * **count** :请求数量。(但是最多只能请求40—50个??这是怎么回事,我目前还没弄清楚!) > https://share.huoshan.com/pages/user/index.html?**to\_user\_id=MS4wLjABAAAA6iUfN2mZ0H4Z7iLtZQ73TYdXoyTUIjk6oDdVWuRtn\_g**×tamp=1597806131&share\_ht\_uid=0&did=67279005018&iid=3113420875114797&utm\_medium=huoshan\_android&tt\_from=copy\_link&app=live\_stream&utm\_source=copy\_link&schema\_url=sslocal%3A%2F%2Fprofile%3Fid%3D75014355319 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 29] ###### 代码及结果: ###### class DY_HSB(): headers = { # 模拟手机 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.s_url=s_url self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 def dyhsb_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ rel_url = str(requests.get(self.url, proxies=proxy, headers=self.headers).url) if 'item' == rel_url.split('/')[4]: # 单个视频 video_name = int(random.random() * 2 * 1000) video_url = 'https://api.huoshan.com/hotsoon/item/video/_source/?item_id=' + \ rel_url.split('=')[1].split('&')[0] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) if '【抖音火山版】' in self.s_url: print("【抖音火山版】: {}.mp4 无水印视频下载完成!".format(video_name)) elif '【火山极速版】' in self.s_url: print("【火山极速版】: {}.mp4 无水印视频下载完成!".format(video_name)) if 'user' == rel_url.split('/')[4]: # 用户视频 ########## # 缺陷:最多支持下载 40--50 个该用户视频。 ########## to_user_id = rel_url.split('=')[1].split('&')[0] info_json = requests.get('https://share.huoshan.com/api/user/info?encrypted_id={}'.format(to_user_id)) item_count = info_json.json()['data']['item_count'] user_name = info_json.json()['data']['nickname'] if os.path.exists(path + user_name + '/'): pass else: os.makedirs(path + user_name + '/') videos_url = 'https://share.huoshan.com/api/user/video?encrypted_id={}&count={}'.format(to_user_id, item_count) video_info = requests.get(videos_url, proxies=proxy, headers=self.headers).json()['data'] for info in tqdm(video_info, desc='正在下载用户 {} 的视频:'.format(user_name)): video_name = int(random.random() * 2 * 1000) video_url = 'https://api.huoshan.com/hotsoon/item/video/_source/?item_id=' + info['item_id'] video = requests.get(video_url, proxies=proxy, headers=self.headers).content with open(path + user_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) if '【抖音火山版】' in self.s_url: print("【抖音火山版】: 用户 {} 的无水印视频下载完成!".format(user_name)) elif '【火山极速版】' in self.s_url: print("【火山极速版】: 用户 {} 的无水印视频下载完成!".format(user_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 30] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 31] -------------------- #### 最右 #### 依旧是通过拿到分享链接,然后抓包分析: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 32] 拿到分享链接: > \#最右\#分享一条有趣的内容给你,不好看算我输。请戳链接>> https://share.izuiyou.com/hybrid/share/post?pid=191652885&zy\_to=applink&share\_count=1&m=ce86942098b72ec745e740e69ab9f6ec&d=fd238824d489ba3c1d65dfb74793074fd42ce27cafa76630b9eecfd7d657f50c&app=zuiyou&recommend=top\_ctr&name=use\_push\_only&title\_type=post ##### 单个视频下载 ##### 基本思路也还是不变,更改设备后查看源码,将部分源码提取出来: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 33] … ![在这里插入图片描述][20200819115012229.png_pic_center] 将这部分源码拿到 [JSON在线解析的网站上去][JSON]: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 34] 虽然提示有错误,不过我们可以编辑一下源码,改正这个错误: 先搜索错误的信息: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 35] 然后修改: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 36] 因为这个参数不影响我们的爬取,所以,无论改成什么字符都可以,**切记一定要双引号!** 随后,经过我的一番查找,终于找到了视频的无水印链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 37] 由于这并不是标准的 **json** 数据,所以,我们还是直接用正则表达式来提取。 ###### 代码及结果 ###### class ZY(): # 最右 headers = { # 模拟成手机 'Host': 'share.izuiyou.com', 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 def zy_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ url_flag = str(self.url).split('/')[3] html = requests.get(self.url, proxies=proxy, headers=self.headers).text flag = re.findall('"imgs":\[{"id":(.*?),"h":', html)[0] video_name = re.findall('{"id":.*?,"share":.*?,"content":"(.*?)","title":"', html)[0].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = re.findall(',"thumb":' + flag + ',"playcnt":.*?"url":"(.*?)","prior', html)[0] \ .replace('u002F', '').replace('\\', '/') video = requests.get(video_url, proxies=proxy).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【最右】: {}.mp4 无水印视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 38] ##### 话题视频下载 ##### 同样的,我们拿到某一话题的链接: > \#最右\#发现一个超给力的话题,快来围观!请戳链接>> https://share.izuiyou.com/topic/429972?m=ce86942098b72ec745e740e69ab9f6ec&d=fd238824d489ba3c1d65dfb74793074fd42ce27cafa76630b9eecfd7d657f50c&app=zuiyou ###### 代码及分析 ###### 对于这一话题,我们在电脑抓包 **XHR** 选项中可以看到有一个 **list** 字段,里面就是关于该话题的视频信息: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 39] **备注:** 因为此次都是用电脑浏览器抓的包,并没有去分析手机端的 **APP** 请求方式,所以对于话题下载。只能下载前 10 个视频,后续有机会或者有需求的话,我会再抓包分析! 对与请求链接:**https://share.izuiyou.com/api/topic/details** ,并没有发生什么变化,但是传参就有点复杂了: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 40] 不过在我几次筛选之后发现有用的参数并不复杂: * app: 默认 “zuiyou” 就好! * d、m、tid: 虽然不知道这个参数是干嘛的,不过我们可以在主页链接中找到。**注意**: 参数 tid 是 **int** 类型的参数。 * ua: 这个就很明显了啊,就是请求的 **User-Agent**。 于是我们就可以构建一下请求负载: 这里需要注意的是:请求负载是 **JSON** 类型的数据,而不是最常见的 **DATA** : ![在这里插入图片描述][20200823172804398.png_pic_center] JSON = { 'app': "zuiyou", 'd': str(self.url).split('=')[2].split('&')[0], 'm': str(self.url).split('=')[1].split('&')[0], 'tid': int(str(self.url).split('/')[4].split('?')[0]), 'ua': "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.125" } 同样的我们发现,在 **video** 字段下,还有一个全是数字的字符串: ![在这里插入图片描述][20200823173013947.png_pic_center] 我们在当前 json 文件中搜索可以发现,在 **img** 字段的信息里有一串一模一样的字段: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 41] ###### 代码及结果: ###### 知道了视频链接保存的地方与请求方式,下面开始编写代码: class ZY(): # 最右 headers = { # 模拟成手机 'Host': 'share.izuiyou.com', 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.105' } def __init__(self, s_url): self.url = re.findall('(https?://[^\s]+)', s_url)[0] # 正则提取字符串中的链接 def zy_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ url_flag = str(self.url).split('/')[3] if 'hybrid' == url_flag: html = requests.get(self.url, proxies=proxy, headers=self.headers).text flag = re.findall('"imgs":\[{"id":(.*?),"h":', html)[0] video_name = re.findall('{"id":.*?,"share":.*?,"content":"(.*?)","title":"', html)[0].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = re.findall(',"thumb":' + flag + ',"playcnt":.*?"url":"(.*?)","prior', html)[0] \ .replace('u002F', '').replace('\\', '/') video = requests.get(video_url, proxies=proxy).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【最右】: {}.mp4 无水印视频下载完成!".format(video_name)) if 'topic' == url_flag: ########### # 缺陷:话题区最多下载 10 个视频 ########### JSON = { 'app': "zuiyou", 'd': str(self.url).split('=')[2].split('&')[0], 'm': str(self.url).split('=')[1].split('&')[0], 'tid': int(str(self.url).split('/')[4].split('?')[0]), 'ua': "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.125" } URL = 'https://share.izuiyou.com/api/topic/details' r = requests.post(URL, json=JSON, proxies=proxy, headers=self.headers) video_info = r.json()['data']['list'] type_name = r.json()['data']['topic']['topic'].replace(' ','') if os.path.exists(path + type_name + '/'): pass else: os.makedirs(path + type_name + '/') for video_info in tqdm(video_info, desc='正在下载类型 【{}】 的视频: '.format(type_name)): video_name = video_info['content'].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] flag = video_info['imgs'][0]['id'] video_url = video_info['videos'][str(flag)]['url'] video = requests.get(video_url, proxies=proxy).content with open(path + type_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【最右】: 类型 【{}】 无水印视频下载完成!".format(type_name)) ###### 小优化: ###### * 1、因为后来我发现在话题区可能有图片的动态,不是视频的话,可能会出错,所以我对可能会出错的地方进行了处理 * 2、当我在测试的过程中发现,有些视频的神评中也含有视频,所以我准备再加一点点代码,把那些也都下载下来: 先找到审评的保存地方: ![在这里插入图片描述][20200823175217469.png_pic_center] 对于神评中的视频,规则和单个视频很相似:在 **video** 字段下,还有一个全是数字的字符串: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 42] 在当前 json 文件中搜索可以发现,在 **img** 字段的信息里有一串一模一样的字段: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 43] 然而,也有可能在神评中没有视频或者没有神评,所以这一次直接把可能出现问题的地方处理掉: # # 上面不做修改 # """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ if 'topic' == url_flag: ########### # 缺陷:话题区最多下载 10 个视频 ########### JSON = { 'app': "zuiyou", 'd': str(self.url).split('=')[2].split('&')[0], 'm': str(self.url).split('=')[1].split('&')[0], 'tid': int(str(self.url).split('/')[4].split('?')[0]), 'ua': "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/84.0.4147.125" } URL = 'https://share.izuiyou.com/api/topic/details' r = requests.post(URL, json=JSON, proxies=proxy, headers=self.headers) video_info = r.json()['data']['list'] type_name = r.json()['data']['topic']['topic'].replace(' ','') if os.path.exists(path + type_name + '/'): pass else: os.makedirs(path + type_name + '/') for video_info in tqdm(video_info, desc='正在下载类型 【{}】 的视频: '.format(type_name)): video_name = video_info['content'].replace(' ','') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] flag = video_info['imgs'][0]['id'] try: video_url = video_info['videos'][str(flag)]['url'] video = requests.get(video_url, proxies=proxy).content with open(path + type_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) except: pass try: video_info1=video_info['god_reviews'][0]['videos'] for a in tqdm(range(len(video_info1)),desc="正在下载该视频下的评论视频:"): flag1=video_info['god_reviews'][0]['imgs'][a]['id'] video_url1=video_info['god_reviews'][0]['videos'][str(flag1)]['url'] video_name = int(random.random() * 2 * 1000) video = requests.get(video_url1, proxies=proxy).content with open(path + type_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) except: pass print("【最右】: 类型 【{}】 无水印视频下载完成!".format(type_name)) 结果: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 44] -------------------- #### VUE #### ##### 单个视频下载 ##### vue平台虽然视频本身没有频台水印,但是却没有给我们提供下载功能,所以我才会编写这段代码: 同样拿到某一个视频的分享链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 45] 拿到的分享链接: > https://v.vuevideo.net/share/post/-5263687500195767823 ###### 抓包与分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 46] 在电脑端打开分享网站后,又检查工具查看,我们所需要的东西都可以很轻松的找到,于是: ###### 代码及结果 ###### class VUE(): # VUEvlog headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59' } def __init__(self, url): self.url = url def vue_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ rel = requests.get(self.url, proxies=proxy, headers=self.headers) video_name = parsel.Selector(rel.text).xpath('//div[@class="videoTitle"]/text()').extract()[0].replace(' ', '') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = parsel.Selector(rel.text).xpath('//div[@class="videoContainer"]/video/@src').extract()[0] video = requests.get(video_url, proxies=proxy).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【VUE】: {}.mp4 视频下载完成!".format(video_name)) 结果: ![在这里插入图片描述][20200902234406254.png_pic_center] ##### 话题视频下载 ##### 对于话题区,我们也还是拿到分享链接: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 47] > https://v.vuevideo.net/share/topics/193 ###### 抓包与分析 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 48] ###### 代码及结果: ###### 按照单个视频下载的方式,同样的能够获得我们所需要的所有信息,每一个 <li>…</li> 标签都包裹着每一个视频的信息,所以: class VUE(): # VUEvlog headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59' } def __init__(self, url): self.url = url def vue_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ rel = requests.get(self.url, proxies=proxy, headers=self.headers) if str(rel.url).split('/')[4] == 'post': # 单个视频 video_name = parsel.Selector(rel.text).xpath('//div[@class="videoTitle"]/text()').extract()[0].replace(' ', '') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = parsel.Selector(rel.text).xpath('//div[@class="videoContainer"]/video/@src').extract()[0] video = requests.get(video_url, proxies=proxy).content with open(path + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【VUE】: {}.mp4 视频下载完成!".format(video_name)) if str(rel.url).split('/')[4] == 'topics': # 主题视频 all_li = parsel.Selector(rel.text).xpath('//div[@class="info-layout"]').extract() topics_name = re.findall('><span>(.*?)</span><', rel.text)[0].replace(' ', '') for li_info in tqdm(all_li, desc="正在下载类型为 {} 的视频:".format(topics_name)): video_name = re.findall('="post-title-text">(.*?)</span></div', li_info)[0].replace(' ', '').replace( ':', '') if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = re.findall('src="(.*?)"', li_info)[1].replace(' ', '') if os.path.exists(path + topics_name + '/'): pass else: os.makedirs(path + topics_name + '/') video = requests.get(video_url, proxies=proxy).content with open(path + topics_name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【VUE】: 类型 【{}】 无水印视频下载完成!".format(topics_name)) 结果: ![在这里插入图片描述][20200902235948661.png_pic_center] -------------------- #### 看看视频 #### 看看视频,是将一部电视剧的**主要情节剪辑下来**,让你在上厕所的时候追完一部剧。 按照我们以前的套路,我们肯定要先拿到视频的分享链接,不过,看看视频并没有给我们提供这样的功能,但是,我们直接分享到QQ时发现,这就是一个分享链接: > https://micro.kankan.com/index?productId=207063&setId=220133&productName=隐秘的角落&userId=-1&userid=-1&moviesId=207063 ###### 抓包与分析 ###### 将链接放到浏览器抓包可以很快的找到视频信息的保存地址: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 49] 同样的我们能够得到全部和单个视频的请求接口。 ###### 代码及结果 ###### 我们对结果进行梳理后,开始编写代码: class KKSP(): # 看看视频 def __init__(self, s_url): self.moviesId = str(s_url).split('=')[-1] print(self.moviesId) self.headers = { 'Host': 'svideo-api.kankan.com', 'Origin': 'https://micro.kankan.com', 'Referer': s_url, 'terminal': 'H5', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44', 'userid': '-1' } def kksp_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ global video_url, video_name url = 'https://svideo-api.kankan.com/microvision/getSetListByMoviesId?moviesId=' + self.moviesId print(url) r = requests.get(url, proxies=proxy, headers=self.headers) video_infos = r.json()['data']['moviesSetList'] name = r.json()['data']['moviesName'] print(name) 但是当我运行以上代码时发现在 ***’Referer’: s\_url*** 的地方出现了错误,时编码的问题: > `UnicodeEncodeError: 'latin-1' codec can't encode characters in position 73-77: ordinal not in range(256)` > 大致翻译为: > `UnicodeEncodeError:“ latin-1”编解码器无法对位置73-77中的字符进行编码:序数不在范围内(256)` > 原因是链接中含有中文。 ###### 小优化 ###### class KKSP(): # 看看视频 def __init__(self, s_url): self.moviesId = str(s_url).split('=')[-1] self.headers = { 'Host': 'svideo-api.kankan.com', 'Origin': 'https://micro.kankan.com', 'Referer': quote(s_url), 'terminal': 'H5', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44', 'userid': '-1' } def kksp_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ global video_url, video_name url = 'https://svideo-api.kankan.com/microvision/getSetListByMoviesId?moviesId=' + self.moviesId print(url) r = requests.get(url, proxies=proxy, headers=self.headers) video_infos = r.json()['data']['moviesSetList'] name = r.json()['data']['moviesName'] if os.path.exists(path + name): pass else: os.makedirs(path + name) video_num = 0 for video_info in tqdm(video_infos, desc="正在下载 {}: ".format(name)): video_num += 1 video_name = '第{}集 '.format(video_num) + video_info['des'] if video_name == '': video_name = int(random.random() * 2 * 1000) if len(str(video_name)) > 20: video_name = video_name[:20] video_url = video_info['moviesSetScreenList'][0]['vodurl'] video = requests.get(video_url, proxies=proxy).content with open(path + name + '/' + str(video_name) + '.mp4', 'wb') as f: f.write(video) print("【看看视频】: {}.mp4 视频下载完成!".format(name)) 结果: ![在这里插入图片描述][20200906164527917.png_pic_center] -------------------- #### 哔哩哔哩 #### 由于B站不同于其他平台的短视频,所以我决定单独写一篇博客: 点击跳转:[Python爬虫: 哔哩哔哩视频下载][Python_] -------------------- #### AcFun #### A站我也单独写了篇文章来介绍:点击跳转:[Python爬虫:AcFun弹幕视频网][Python_AcFun] -------------------- #### ZzzFun #### [Python爬虫:ZzzFun动漫视频网][Python_ZzzFun] -------------------- #### 西瓜视频 #### ###### 抓包分析 ###### 对于西瓜视频来说,既有安卓端的APP,也有网页版的主站。 但是呢,经过我的观察与验证发现,无论是哪个平台,请求资源的链接都是一样的,举个例子: > 在安卓端拿到的分享链接:【[https://v.ixigua.com/J4wB5ek/][https_v.ixigua.com_J4wB5ek] 】 > 与在浏览器端拿到的链接:【[https://www.ixigua.com/6873787245292159495/][https_www.ixigua.com_6873787245292159495]】 > 其实是定向到了同一个链接下:[https://www.ixigua.com/6873787245292159495/][https_www.ixigua.com_6873787245292159495] > ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 50] > 其实说白了就是,在安卓端拿到的分享链接是一个**短的映射链接**,而在浏览器地址栏显示的才是**映射到的真正的地址链接**,(不知道我说明白没有哈哈~~) 在我明白了以上的对应关系之后,我又发现了一个有用的信息,那就是: > **APP端和电脑网页端在线播放时,视频本身就是加载的无水印的链接,而当我们用手机浏览器打开时会发现,即使是在线观看,也是有水印的视频。** 知道了这些,那我们就可以确定,我们的请求头中 **user-agent** 字符,不能是手机的了。 既然APP端和电脑浏览器端都是一样的请求链接,那我们就不用再用APP端来获取链接了,直接再浏览器网页端点击岂不是更香~~ 我们先随便点击一个视频打开调试工具: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 51] 让视频播放几秒钟后发现,网站一直在反复请求两个相识的链接,这是怎么回事呢?有种似曾相识的感觉… **没错~~就是和B站的加载机制相同:分别加载音频和视频。** 我们先来查看网页源码:找到渲染完成的视频标签的位置后发现: ![在这里插入图片描述][20201211213509203.png_pic_center] 每个视频都是以 [**blob:https://…**][blob_https] 的形式出现的。那么这条路就是行不通的。 接下来再来看看有没有什么可供使用的接口或者JSON数据,答案是:全都没有。这可就难办了,看着那些请求链接,有很多的参数,不过我发现:链接中的 **?** 之后所有字段都不影响我们去请求资源,真正有用的就只有 **?** 前面的字段。 > 举个例子: > 链接一:https://v3-xg-web.ixigua.com/599d2dfe9869f497674442f1eb94a612/5fd385d0/video/tos/cn/tos-cn-vd-0026/f99dcd1c27af4b5d82fe4cd1be06b3b9/media-video-avc1/?a=1768&br=8283&bt=2761&cd=0%7C0%7C0&cr=0&cs=0&cv=1&dr=0&ds=4&er=0&l=202012112139480100220282230D1D20F6&lr=default&mime\_type=video\_mp4&qs=0&rc=ajhlc2kzc280djMzZDczM0ApZTg8NTg2Mzw4Nzc1ZTM0ZWdecTZzNC1famdfLS02LS9zcy1hXmMxMGAuY2NfYzQwLjM6Yw%3D%3D&vl=&vr=&range=0-1826 > 链接二:https://v3-xg-web.ixigua.com/8487c167d9680b36f5b19e039114f30d/5fd385d0/video/tos/cn/tos-cn-vd-0026/f99dcd1c27af4b5d82fe4cd1be06b3b9/media-audio-und-mp4a/?a=1768&br=0&bt=0&cd=0%7C0%7C0&cr=0&cs=0&cv=1&dr=0&ds=&er=0&l=202012112139480100220282230D1D20F6&lr=default&mime\_type=video\_mp4&qs=0&rc=ajhlc2kzc280djMzZDczM0ApZ15xNnM0LV9qZ18tLTYtL3NzOmM%3D&vl=&vr=&range=0-1743 那么中间的那些字段到底是怎么来的呢?我对每个字段进行搜索,结果连一条消息都没有找到,说明这个链接的参数**没有在别的地方先生成或者加载**。而是直接请求的该链接… 并且后来我发现,同一个视频,浏览器刷新后,参数是会改变的,并非像之前那样是固定生成的链接,所以,我们还得另辟途径~~ > 在这里,我就不提我遇到的那些坑了,(怕你们笑话,哈哈哈~) > 我直接开始解释链接的加载位置。 我们打开某个视频的网页源码: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 52] 咦~~~~ 只有 **23** 行数据。不过我们都被骗了~~因为我发现在我浏览器的右下角有个这个东西: ![在这里插入图片描述][20201211215322391.png_pic_center] 原来有很多数据都被写在了一行… 把滚动条往右一拉,才发现有好多的JSON数据啊,话不多说,我们将之前的视频播放时加载的链接拿来一搜索,结果: ![在这里插入图片描述][20201211215625264.png_pic_center] 我去,这是怎么回事,我又将全部的网页源码拷贝出来,放在了我的前端编译器上进行格式化: ![在这里插入图片描述][20201211215827671.png_pic_center] 呵,数据藏得还不少!!! 我从上到下的继续翻看源码,发现,视频的一些信息确实是在这里: 就比如视频的名字: ![在这里插入图片描述][20201211220026806.png_pic_center] 紧接着我又发现了与视频清晰度相关的一些信息: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 53] 那么在这里是不是隐藏这一些视频的请求信息呢? 于是我又继续查找,知道我发现了一些重要的信息: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 54] 这…名字取得应该够明白了吧,确实是验证了我们之前所说的,该网站是将视频和音频分开请求的。然后我开始分析每一个参数到底是什么,不过我一眼 就看上了一个参数: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 55] **main\_url** :看到这个 **main** 我就觉得它不简单,于是我就先拿他下手: > **"main\_url"**:“aHR0cD…ZyPQ==” (太长了,我就用…代替了) 先拿出一个来看一看,后面的两个等号很熟悉吧,一串字符后面跟着等号,这让我以下就想到了 **BASE64** 加密,不管怎么说,我们先拿出来验证一下: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 56] 将链接拿到浏览器打开发现,结果还真是我们所要寻找的链接,那么按照这个规矩,音频的链接也是这么提取的,所以我们开始编写代码: class XGSP: main_headers = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'cache-control': 'max-age=0', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'none', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55' } def __init__(self, s_url): self.url = s_url def XGSP_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ r = requests.get(self.url, headers=self.main_headers) r.encoding = 'utf-8' video_info = (re.findall('"packerData":{"video":(.*?)}}}},"', r.text)[0] + "}}}}").replace("undefined", '"undefined"') video_json = json.loads(video_info) video_name = video_json["title"].replace("|", "-").replace(" ", "") print("视频名:" + video_name) video_url = base64.b64decode( video_json['videoResource']['dash']['dynamic_video']['dynamic_video_list'][-1]['main_url']).decode("utf-8") print("视频链接:" + video_url) audio_url = base64.b64decode( video_json['videoResource']['dash']['dynamic_video']['dynamic_audio_list'][-1]['main_url']).decode("utf-8") print("音频链接:" + audio_url) 注解: > * **细心的朋友应该会发现**,按照这个流程写下来的代码,获取到的网页源码全是**乱码**。那是在浏览器端复制过来的请求头中会有这样的字段:**accept-encoding: gzip, deflate, br**,但是我并没有写上去,反而在请求分享链接时进行了如下的设置:**r.encoding = 'utf-8’**,这样才能使网页源码正常爬取。 > * **video\_info = (re.findall(’“packerData”:\{“video”: (.\*?)\}\}\}\},"’, r.text)\[0\] + “\}\}\}\}”).replace(“undefined”, ‘“undefined”’)** :为了减少需要再次清晰数据,我们直接用正则表达式提取出视频和音频的链接部分。因为视频不同, **video** 字段后的一个字段会有所不同,所以我直接拿比较明显的 **4** 个 \*\*” \} “\*\*来截取,然后拼接上。 > * **base64.b64decode(video\_json\[‘videoResource’\]\[‘dash’\]\[‘dynamic\_video’\]\[‘dynamic\_video\_list’\]\[-1\]\[‘main\_url’\]).decode(“utf-8”)** :则是**base64解码**。 现在我们就可以拿到每一次的视频和音频的链接了(我这里以最高的清晰度来作为演示)。 class XGSP: main_headers = { # # 不变 # } video_headers = { 'accept': '*/*', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'origin': 'https://www.ixigua.com', 'referer': 'https://www.ixigua.com/', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57' } def __init__(self, s_url): self.url = s_url def XGSP_download(self): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 """ # # 不变 # with open(path + video_name + ".flv", "wb") as f: f.write(requests.get(video_url, headers=self.video_headers).content) print("视频文件下载完成...") with open(path + video_name + "-1.flv", "wb") as f: f.write(requests.get(audio_url, headers=self.video_headers).content) print("音视频均下载完成,即将开始拼接...") 现在我们已经下载好了视频和音频,接下来就需要将它们合并为一个视频,既然加载方式和B站很相似,那么下载方式也应该差不多: [Python爬虫:哔哩哔哩(bilibili)视频下载][Python_] ###### 类源码 ###### 或者直接参考我的代码: class XGSP: main_headers = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'cache-control': 'max-age=0', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'none', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55' } video_headers = { 'accept': '*/*', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'origin': 'https://www.ixigua.com', 'referer': 'https://www.ixigua.com/', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57' } def __init__(self, s_url): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 :param s_url: 视频分享链接 """ self.url = s_url def XGSP_download(self): r = requests.get(self.url, headers=self.main_headers) r.encoding = 'utf-8' video_info = (re.findall('"packerData":{"video":(.*?)}}}},"', r.text)[0] + "}}}}").replace("undefined", '"undefined"') video_json = json.loads(video_info) video_name = video_json["title"].replace("|", "-").replace(" ", "") print("视频名:" + video_name) video_url = base64.b64decode( video_json['videoResource']['dash']['dynamic_video']['dynamic_video_list'][-1]['main_url']).decode("utf-8") print("视频链接:" + video_url) audio_url = base64.b64decode( video_json['videoResource']['dash']['dynamic_video']['dynamic_audio_list'][-1]['main_url']).decode("utf-8") print("音频链接:" + audio_url) with open(path + video_name + ".flv", "wb") as f: f.write(requests.get(video_url, headers=self.video_headers).content) print("视频文件下载完成...") with open(path + video_name + "-1.flv", "wb") as f: f.write(requests.get(audio_url, headers=self.video_headers).content) print("音视频均下载完成,即将开始拼接...") video_add_mp3("D:/ffmpeg-2020-09-30-essentials_build/bin/", path, path + video_name + ".flv", path + video_name + "-1.flv") def video_add_mp3(ffmpeg_path, save_path, file1_path, file2_path): """ CSDN :高智商白痴 CSDN个人主页:https://blog.csdn.net/qq_44700693 ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a copy output.mp4 视频添加音频 :param ffmpeg_path: ffmpeg的安装 bin 路径 :param save_path: 文件保存路径 :param file1_path: 传入视频频文件的路径 :param file2_path: 传入音频文件的路径 :return: """ mp4_name = file1_path.split('/')[-1].split('.')[0] + '-temp.mp4' mp3_name = file1_path.split('/')[-1].split('.')[0] + '-temp.mp3' outfile_name = file1_path.split('.')[0] + '.mp4' os.system(r'%sffmpeg -i %s %s' % (ffmpeg_path, file1_path, save_path + mp4_name)) os.system(r'%sffmpeg -i %s %s' % (ffmpeg_path, file2_path, save_path + mp3_name)) os.system(r'%sffmpeg -i %s -i %s -c:v copy -c:a copy %s' % ( ffmpeg_path, save_path + mp4_name, save_path + mp3_name, outfile_name)) os.remove(save_path + mp4_name) os.remove(save_path + mp3_name) os.remove(file1_path) os.remove(file2_path) 因为不知道原视频的真实格式,所以将视频和音频的格式都手动改为 **flv** 格式,在合并前进行格式转换。 ###### 结果 ###### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70] -------------------- ### 编写中。。。 ### [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center]: /images/20221124/21220a69c8954f4f80b97c194961e1a8.png [Link 1]: https://blog.csdn.net/qq_44700693 [https_blog.csdn.net_qq_44700693_article_details_108089085]: https://blog.csdn.net/qq_44700693/article/details/108089085 [Python]: https://blog.csdn.net/qq_44700693/article/details/106796782 [Python 1]: https://blog.csdn.net/qq_44700693/article/details/113826111 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center]: /images/20221124/bc47e69aa56a4224bf6907cfa6ec3f36.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 1]: /images/20221124/bfb3184cc07a412899284152f0d245c4.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 2]: /images/20221124/44c5b7e54332420bb168d844a92b1d07.png [20200818100639452.png_pic_center]: /images/20221124/c600d5e108b84614aa4c305be3bec2d8.png [20200818100716137.png_pic_center]: /images/20221124/1458adbb97d445a790822f74683c7a61.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 1]: /images/20221124/20cd362225914987bf7d3101027cf089.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center_pic_center 3]: /images/20221124/5c69511594fc4c6bb46d14c9fc57856a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 2]: /images/20221124/d193654d7ed5470f80b3f52007bd2254.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 3]: /images/20221124/0038a662c09340b7b726ac64d2955598.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 4]: /images/20221124/4363bb00c6874345a0234061aea6f872.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 5]: /images/20221124/81108eceaa194bb9acf17729ea76b553.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 6]: /images/20221124/922c87b5790440d5a8f1d67324f988cc.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 7]: /images/20221124/77e71923d7534b77bb8ad2d171bf4145.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 8]: /images/20221124/88e1996ebdce464cac3820a6c277c5f4.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 9]: /images/20221124/eb3829a45ac7453fa1e610be1c54663f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 10]: /images/20221124/19740630a674433a97e45f04189255f7.png [20200818114144922.png_pic_center]: /images/20221124/c0453eeb83a54671b9cc5a0c63eb7ca8.png [20200818114211111.png_pic_center]: /images/20221124/764c7a39e6624d9da53a7c883f882866.png [20200818122019841.gif_pic_center]: /images/20221124/227d222da96241a982882e1ad5343f22.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 11]: /images/20221124/2e3841c527c742e4a4f2c841b2ba1fa6.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 12]: /images/20221124/80c6791f6c0a487d8c79502f29abe229.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 13]: /images/20221124/00dd215884de4f0dad721e620641b41a.png [20200818163856658.png_pic_center]: /images/20221124/4bd22ade37de4bdb8dd65818952be402.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 14]: /images/20221124/b71fcde274bd417eac42fd271e81f801.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 15]: /images/20221124/04470856a87e41a6bf78ecbae4af9670.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 16]: /images/20221124/0c2df811594f434b84f88f5cad03ac22.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 17]: /images/20221124/11c92221d3d642fca01213a2125554aa.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 18]: /images/20221124/632735e37f9e4f1ba93f3b1c4c83e219.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 19]: /images/20221124/c78a3c9aaa8a40c4992fce7cbd6df1b3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 20]: /images/20221124/287274c9a97748df8bfc464fc45baa2a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 21]: /images/20221124/6914142b9a4a4030a8d5bf9ae9d62361.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 22]: /images/20221124/4cd3e0b5a6a941eca1ede695de4d1dcb.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 23]: /images/20221124/46be96e817b84cea998a187eed4ec21e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 24]: /images/20221124/db58759a81f84427997c7c5176fa2a97.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 25]: /images/20221124/c2d0a55d3d724f0990fc719422175def.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 26]: /images/20221124/486a735550eb423e9b2ef8f2d747009c.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 27]: /images/20221124/27fd4b42bab446ae92f23becc46fd7f7.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 28]: /images/20221124/d56b2a43082c4aacbd0fa8695f679e6f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 29]: /images/20221124/7c179098da8549cc8533e5fe3ae14ab0.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 30]: /images/20221124/17713efcece747feae549d721fc53042.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 31]: /images/20221124/ba8a8c5875774c27a40c3fe370121c87.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 32]: /images/20221124/03d9e8d061fa4666b6a6a1bedc44b380.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 33]: /images/20221124/dd59373442584ceab82f7a2b9b00fe48.png [20200819115012229.png_pic_center]: /images/20221124/0fccce1479f54e839a826a8d7d47961c.png [JSON]: http://json.cn/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 34]: /images/20221124/f9ad8c2e86aa4d9dac3985cc32c14bf4.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 35]: /images/20221124/cfb7bb8e6fca47ebaf7aed1346df5b73.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 36]: /images/20221124/2e86616356d649838665a6aaed14d4f9.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 37]: /images/20221124/94ebd33728624f39b593d5ac2f036e37.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 38]: /images/20221124/a18319683a6b4a818889e4630271a654.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 39]: /images/20221124/d943733f2cbb468493522fff8e623f80.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 40]: /images/20221124/e9093661a04b4d14a26c105b33992a78.png [20200823172804398.png_pic_center]: /images/20221124/1e461a8d60e34e8c9d7895beb6ec1116.png [20200823173013947.png_pic_center]: /images/20221124/af9be032ec5c4f6bb014357b51ff6ce4.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 41]: /images/20221124/4eb1961723cd4cbd8bbadc8ccdec68bb.png [20200823175217469.png_pic_center]: /images/20221124/98044d8fa3344d5a947c13d725d41da7.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 42]: /images/20221124/656ed4adeab54e128ecf4a1fc717b295.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 43]: /images/20221124/a9ee4375fcc9452499ab5d3bb7a90813.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 44]: /images/20221124/c85d3f23e8b34447b23fc363b24d7b63.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 45]: /images/20221124/bf5f23fa6c574be38ee1fca9da2c1d53.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 46]: /images/20221124/1663096c97c9434eaa809b73ae8d229c.png [20200902234406254.png_pic_center]: /images/20221124/b764469f90754aac86fb0210d97e5c6f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 47]: /images/20221124/daf37ba386c84d91bba823d815a0a788.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 48]: /images/20221124/64a4b6e3972541408d70360d3d08334a.png [20200902235948661.png_pic_center]: /images/20221124/ca2cbc6fc65249f4bfec5f34381b42bb.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 49]: /images/20221124/567a16d49030430ba761ec8fbe834407.png [20200906164527917.png_pic_center]: /images/20221124/ec171cfb6da94bbebbc3c5abca5ef3f4.png [Python_]: https://blog.csdn.net/qq_44700693/article/details/108828909 [Python_AcFun]: https://blog.csdn.net/qq_44700693/article/details/109124334 [Python_ZzzFun]: https://blog.csdn.net/qq_44700693/article/details/109924262 [https_v.ixigua.com_J4wB5ek]: https://v.ixigua.com/J4wB5ek/ [https_www.ixigua.com_6873787245292159495]: https://www.ixigua.com/6873787245292159495/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 50]: /images/20221124/6e88b7f6b53c42e99aa221a3616d55b2.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 51]: /images/20221124/1c3c765564604e0288c350a6f0963e9f.png [20201211213509203.png_pic_center]: /images/20221124/ab8e0400cb7a4654b7cd05d801e51b92.png [blob_https]: https://my.oschina.net/sallency/blog/3014652 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 52]: /images/20221124/ff69d11d772f464db80ab1a154d09b9f.png [20201211215322391.png_pic_center]: /images/20221124/a48c6c455e7749b2badd4ceefe65b77e.png [20201211215625264.png_pic_center]: /images/20221124/1884cb82cb7b4b7ca6ea0cefa9a8bc26.png [20201211215827671.png_pic_center]: /images/20221124/441bcd3794e148ec804917fa37b33e9b.png [20201211220026806.png_pic_center]: /images/20221124/9f00cd6989b846a48b4dadcf86bf0234.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 53]: /images/20221124/5110ff2bcbdc49d494996f766cf7289f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 54]: /images/20221124/a2af774593234b4fbfca0b2d3c5ff295.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 55]: /images/20221124/17e5ed7169c14864a04a05b7bab897b3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70_pic_center 56]: /images/20221124/afbfa2a9c9f944f294c2e8d00ef50b77.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAwNjkz_size_16_color_FFFFFF_t_70]: /images/20221124/a666da20dc634e70a08ab951530c8ac7.png
相关 Python爬虫:短视频平台无水印下载(上) ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ub 心已赠人/ 2022年11月29日 03:05/ 0 赞/ 333 阅读
相关 Python实现超简单【抖音】无水印视频批量下载 前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。 作者:python乱炖 PS:如有需要P 短命女/ 2022年11月20日 11:56/ 0 赞/ 420 阅读
相关 一篇文章教会你使用Python下载抖音无水印视频 今天小编要跟大家分享的是,利用Python如何下载抖音无水印的视频;大家可能要问了,这个有什么用呢?当然有用了。那么有什么用呢?下面小编跟大家详细说说。 众所周知,由于如今短 偏执的太偏执、/ 2022年11月05日 03:06/ 0 赞/ 393 阅读
相关 Python爬虫:皮皮虾短视频无水印下载(新版) ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ub 我会带着你远行/ 2022年10月30日 01:21/ 0 赞/ 443 阅读
相关 【Python爬虫】全国最大短视频平台,美女视频数据批量下载(长期有效,建议收藏) 前言 现在自媒体平台上经常有一些视频素材需要保存下来,但是大部分平台下载下来都带上了平台水印,影响视频美观。这次我们用爬虫,可以爬到高清无水印的视频 本文知识点 一时失言乱红尘/ 2022年09月17日 01:54/ 0 赞/ 173 阅读
相关 2021最新版Python爬取无水印小姐姐短视频,超级简单!(附视频/源码) ![在这里插入图片描述][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA5Zeo5a2m57yW5 刺骨的言语ヽ痛彻心扉/ 2022年09月09日 02:09/ 0 赞/ 165 阅读
相关 短信平台 下载 c# 今天上传了短信平台为各位朋友做参考 内容包括: CMPP2.0短信客户端程序 SGIP1.2短信客户端程序 SMGP3.0短信客户端程序 SQL2005脚本 简单的 一时失言乱红尘/ 2022年08月04日 15:47/ 0 赞/ 130 阅读
相关 下载无水印视频插件版使用教程 什么是无水印视频下载?当我们在观看腾讯视频时会发现腾讯视频右上角有个水印如下图: 如果我们玩抖音或者其它平台时,下载这个视频有水印时不会被推广的。所以我们需要一些无水印的... 朱雀/ 2021年11月27日 06:08/ 1 赞/ 12651 阅读
相关 Python3之抖音无水印视频解析脚本 `因为服务器太渣,链接就不放出来了。记住返回的这个数据结构就可以了!` 在抖音,记录美好生活智商不在线的一瞬间 http://v.douyin.com/U3a3QD/ ╰半夏微凉°/ 2021年10月24日 00:11/ 0 赞/ 739 阅读
相关 python3 抖音短视频链接去水印下载视频到本地 > 基于近段时间对抖音,快手,秒拍等视频抓取一直想搞一下。加了个QQ群,里面全是自媒体,就是抖音、快手、秒拍的视频搬运工,把一个平台搬到另外一个平台上,去除水印。降低被干掉的危 £神魔★判官ぃ/ 2021年09月15日 15:42/ 0 赞/ 584 阅读
还没有评论,来说两句吧...