Python爬虫:ZzzFun动漫视频网

news/2024/11/17 19:36:00/

在这里插入图片描述
提醒:转载请标明作者和原文链接!!!

CSDN个人主页: 高智商白痴
原文地址: https://blog.csdn.net/qq_44700693/article/details/109924262

日常跳转:

      • 前言
        • 分析
        • 获取m3u8文件链接
        • 下载m3u8文件
        • 源码及结果
        • 最后

前言

我们都知道爬虫分为两类,分别是 通用爬虫聚焦爬虫 ,我在这次的实例说明前给大家简要说明一下:

1、通用爬虫
通用网络爬虫是捜索引擎抓取系统(Baidu、Google等)的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
但是搜索引擎蜘蛛的爬取是被定义了一定的规则的,它需要遵从一些命令或文件的内容,如标注为 nofollow 的链接,或者是 Robots 协议。
2、聚焦爬虫
聚焦爬虫是 “面向特定主题需求” 的一种网络爬虫程序,它与通用搜索引擎爬虫的区别在于: 聚焦爬虫在实施网页抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息。而我们将要学习的,就是聚焦爬虫。

而在编写 聚焦爬虫 时,免不了会遇到一些反扒机制,如:

  • 1、headers and referer 反爬机制
  • 2、IP 限制
  • 3、UA限制
  • 4、验证码反爬虫或者模拟登陆

其实到目前为止,我已经写过一些关于一些 反反爬 的案例,大家可以自行去了解:https://blog.csdn.net/qq_44700693/category_9835663.html


分析

而今天呢,我又将会给大家介绍另一种反爬的情况:ZzzFun动漫视频网 - ( ̄﹃ ̄)~zZZ

针对这个网站会有一个不同于其他网站的特性:
在这里插入图片描述
不知道各位有没有发现什么,没错!那就是该网站某些页面无法调试,否则会 直接跳转到网站首页!这是因为在网页的某一请求资源下含有以下的 JS源码

//debug调试时跳转页面
var element = new Image();
Object.defineProperty(element,'id',{get:function(){window.location.href="http://www.zzzfun.com"}});
console.log(element);

先不要管这段代码从哪里来,我后面会说明。不光是代码,我甚至就连代码的原注释都复制过来了,应该已经说的够详细了吧~~

针对这样的网站,像以前单纯的用浏览器抓包已经满足不了我们了,所以就需要用一点特殊的手段,使用第三方的工具 Fiddler 来进行抓包。

关于 Fiddler 的内容就在我之前的一篇文章里,我还会持续更新用法的~~
Fiddler:Fiddler新旧版抓包相关总结

说干就干,我这次使用的是最新版的 Fiddler Everywhere ,毕竟界面简洁干净嘛~

我们还是打开某一动漫的详情介绍页面后打开 Fiddler Everywhere 开始抓取请求:
在这里插入图片描述

当页面全部加载完成后,我们就可以关闭 Fiddler Everywhere 了,避免我们的误操作会造成多余的抓取信息。

当浏览器加载完成后我们就可以开始挨个儿查看所抓取到的信息:

在这里插入图片描述
当我们挨个儿查看时发现,在某一次与当前剧集链接相同的请求时,点击 Preview ,会发现当前页面的所有信息都已经加载完成了,除了视频信息~~ 那么视频信息就有可能是 AJAX 或者其他方式来进行的界面局部更新。

我们知道了视频的加载方式,那么接下来就可以开始寻找视频的来源到底时什么了~~
在这里插入图片描述
在第一遍大概浏览的时候我发现,在上图的位置,浏览器请求了一个 m3u8 文件,而这估计就是视频的信息了。
那么反过来说,这是一个m3u8 文件的请求链接,那么在这之前,就肯定会有一个地方对这个链接进行了参数生成然后开始请求,并且我发现同一个视频,链接会发生变化,并且每一条链接的时效性很短很短!!!

综合现有的信息我一开始猜测可能是用 JS 实现的参数生成,结果并不是,不信你继续往下看~~
既然知道了这一次请求的链接参数,那么我们就开始寻找参数生成的位置:我又挨个儿的对返回数据进行查找,终于让我找到了链接来源:
在这里插入图片描述
在这里就还可以顺便把我之前埋的坑给填了:
在这里插入图片描述


获取m3u8文件链接

而且是完全拼接好的链接,那这就简单很多了,我们可以直接从该链接下手进行抓取,然后通过正则表达式来进行链接的提取:
根据抓包信息来破解反爬:

def user_ui():"""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693"""main_headers = {'Host': 'www.zzzfun.com','Connection': 'keep-alive','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','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','Referer': "http://www.zzzfun.com/vod-detail-id-1934.html",'Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'}video_urls = 'http://www.zzzfun.com/static/danmu/bed-bofang.php?1934/01.m3u8'r = requests.get(video_urls, proxies=proxy, headers=main_headers)m3u8_url = re.findall("video.src = '(.*?)';", r.text)[0]print(m3u8_url)

得到以下链接:
http://service-agbhuggw-1259251677.gz.apigw.tencentcs.com/pay/hlsjiami/1606222851/8a4dcc584f6a406890cb0551f2753082/1934/01.m3u8

获取了某一集的视频信息,接下来就要开始分析这个新的请求链接的参数:
通过对多集链接的查看可以很明了的看出参数的构造,不信你看:

同动漫不同集
第一集:http://www.zzzfun.com/static/danmu/bed-bofang.php?1934/01.m3u8
第二集:http://www.zzzfun.com/static/danmu/bed-bofang.php?1934/02.m3u8
第二集:http://www.zzzfun.com/static/danmu/bed-bofang.php?1934/03.m3u8


不同动漫
动漫一:http://www.zzzfun.com/vod-detail-id-1916.html
动漫二:http://www.zzzfun.com/vod-detail-id-1929.html
动漫三:http://www.zzzfun.com/vod-detail-id-1913.html

根据以上的信息我们可以很快的看出参数的构造,所以我们就可以写出如何爬取不同的集数了,但是总不能爬取每一个动漫都要输入下载的集数吧,所以这就体现出视频详情页的重要性了,我们可以从视频详情页找到每一集的信息,并且顺手获取了动漫的名字:

def user_ui(videos_url):"""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693:param videos_url: 视频的详情页链接:return:"""main_headers = {'Host': 'www.zzzfun.com','Connection': 'keep-alive','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','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','Referer': videos_url,'Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'}r = requests.get(videos_url, headers=main_headers)video_name = re.findall("<title>(.*?)详情介绍-.*?</title>", r.text)[0].replace(" ", '')video_nums = len(parsel.Selector(r.text).xpath('//div[@class="episode-wrap"]/ul[1]/li'))video_id = videos_url.split("-")[-1].split('.')[0]video_urls = ['http://www.zzzfun.com/static/danmu/bed-bofang.php?{}/{:0>2d}.m3u8'.format(video_id, num) for num inrange(1, video_nums + 1)]rel_path = path + video_nameif os.path.exists(rel_path):passelse:os.makedirs(rel_path)for url in video_urls:r = requests.get(url, proxies=proxy, headers=main_headers)m3u8_url = re.findall("video.src = '(.*?)';", r.text)[0]name = "第" + url.split('/')[-1].split('.')[0] + "话"print(name + " ---> " + m3u8_url)if __name__ == '__main__':print("""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693""")videos_url = input("请输入视频的详情页链接: ")user_ui(videos_url)

正则表达式是真的香~~~

在这里插入图片描述


下载m3u8文件

到此我们已经获取了一个动漫所需的信息以及下载的链接,接下来就可以开始研究如何下载的。

我在之前的几篇文章中都提到过 m3u8文件 的下载方式:如最近的这篇:Python爬虫:AcFun弹幕视频网

核心思想都是 :Python爬虫:用最普通的方法爬取ts文件并合成为mp4格式

不过在这个例子中会有一点点的修改:

  • 1、对于下载 m3u8 文件视频信息时头文件有所不同。
  • 2、视频信息链接中没有 .ts 字段。
class Download:"""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693"""urls = []m3u8_headers = {'Host': 'service-agbhuggw-1259251677.gz.apigw.tencentcs.com','Connection': 'keep-alive','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','Accept': '*/*','Origin': 'null','Sec-Fetch-Site': 'cross-site','Sec-Fetch-Mode': 'cors','Sec-Fetch-Dest': 'empty','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'}def __init__(self, name, m3u8_url, download_path):""":param name: 视频名:param m3u8_url: 视频的 m3u8文件 地址:param path: 下载地址"""self.video_name = nameself.path = download_pathself.f_url = m3u8_urlwith open(self.path + '/{}.m3u8'.format(self.video_name), 'wb')as f:f.write(requests.get(m3u8_url, headers=self.m3u8_headers).content)def get_ts_urls(self):with open(self.path + '/{}.m3u8'.format(self.video_name), "r") as file:lines = file.readlines()for line in lines:if 'pgc-image' in line:self.urls.append(line.replace('\n', ''))def start_download(self):self.get_ts_urls()for url in tqdm(self.urls, desc="正在下载 {} ".format(self.video_name)):video_headers = {'Host': re.findall("https://(.*?)/obj/", str(url))[0],'Connection': 'keep-alive','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','Accept': '*/*','Origin': 'http://www.zzzfun.com','Sec-Fetch-Site': 'cross-site','Sec-Fetch-Mode': 'cors','Sec-Fetch-Dest': 'empty','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'}movie = requests.get(url, headers=video_headers)with open(self.path + '/{}.flv'.format(self.video_name), 'ab')as f:f.write(movie.content)os.remove(self.path + '/{}.m3u8'.format(self.video_name))

源码及结果

import os
import re
import parsel
import requests
from tqdm import tqdmpath = './'class Download:urls = []m3u8_headers = {'Host': 'service-agbhuggw-1259251677.gz.apigw.tencentcs.com','Connection': 'keep-alive','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','Accept': '*/*','Origin': 'null','Sec-Fetch-Site': 'cross-site','Sec-Fetch-Mode': 'cors','Sec-Fetch-Dest': 'empty','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'}def __init__(self, name, m3u8_url, download_path):"""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693:param name: 视频名:param m3u8_url: 视频的 m3u8文件 地址:param path: 下载地址"""self.video_name = nameself.path = download_pathself.f_url = m3u8_urlwith open(self.path + '/{}.m3u8'.format(self.video_name), 'wb')as f:f.write(requests.get(m3u8_url, headers=self.m3u8_headers).content)def get_ts_urls(self):with open(self.path + '/{}.m3u8'.format(self.video_name), "r") as file:lines = file.readlines()for line in lines:if 'pgc-image' in line:self.urls.append(line.replace('\n', ''))def start_download(self):self.get_ts_urls()for url in tqdm(self.urls, desc="正在下载 {} ".format(self.video_name)):video_headers = {'Host': re.findall("https://(.*?)/obj/", str(url))[0],'Connection': 'keep-alive','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','Accept': '*/*','Origin': 'http://www.zzzfun.com','Sec-Fetch-Site': 'cross-site','Sec-Fetch-Mode': 'cors','Sec-Fetch-Dest': 'empty','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'}movie = requests.get(url, headers=video_headers)with open(self.path + '/{}.flv'.format(self.video_name), 'ab')as f:f.write(movie.content)os.remove(self.path + '/{}.m3u8'.format(self.video_name))def user_ui(videos_url):"""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693:param videos_url: 视频的详情页链接:return:"""main_headers = {'Host': 'www.zzzfun.com','Connection': 'keep-alive','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69','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','Referer': videos_url,'Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6'}r = requests.get(videos_url, headers=main_headers)video_name = re.findall("<title>(.*?)详情介绍-.*?</title>", r.text)[0].replace(" ", '')video_nums = len(parsel.Selector(r.text).xpath('//div[@class="episode-wrap"]/ul[1]/li'))video_id = videos_url.split("-")[-1].split('.')[0]video_urls = ['http://www.zzzfun.com/static/danmu/bed-bofang.php?{}/{:0>2d}.m3u8'.format(video_id, num) for num inrange(1, video_nums + 1)]rel_path = path + video_nameif os.path.exists(rel_path):passelse:os.makedirs(rel_path)for url in video_urls:r = requests.get(url, headers=main_headers)m3u8_url = re.findall("video.src = '(.*?)';", r.text)[0]name = "第" + url.split('/')[-1].split('.')[0] + "话"Download(name, m3u8_url, rel_path).start_download()if __name__ == '__main__':print("""CSDN :高智商白痴CSDN个人主页:https://blog.csdn.net/qq_44700693""")videos_url = input("请输入视频的详情页链接: ")user_ui(videos_url)

结果:
在这里插入图片描述


最后

最后给个小提醒:
如果你出现了这个错误提醒:IndexError: list index out of range
那么你就该检查下你的浏览器打开该网页时是不是这样的:
在这里插入图片描述

解决方法很简单,就是手动点开它就好了,然后在此运行代码~~


http://www.ppmy.cn/news/475102.html

相关文章

php验证码实现代码(3种)验证类

验证码在表单实现越来越多了&#xff0c;但是用js的写的验证码&#xff0c;总觉得不方便&#xff0c;所以学习了下php实现的验证码。 好吧&#xff0c;其实是没有事情干&#xff0c;但是又不想浪费时间&#xff0c;所以学习了下php实现验证码。正所谓&#xff0c;技多不压身。而…

漫画商城的设计与实现

其他项目&#xff0c;点击作者主页 目录 1 系统简介 2 系统相关技术 2.1开发工具和开发环境介绍 2.2Django框架详述 2.3MySQL详述 3 需求分析 3.1 功能需求分析 3.2 可行性分析 3.2.1 经济可行性 3.2.2 技术可行性 3.2.3 操作可行性 4 系统设计 4.1系统总体设计…

php实现验证码

验证码在表单实现越来越多了&#xff0c;但是用js的写的验证码&#xff0c;总觉得不方便&#xff0c;所以学习了下php实现的验证码。好吧&#xff0c;其实是没有事情干&#xff0c;但是又不想浪费时间&#xff0c;所以学习了下php实现验证码。正所谓&#xff0c;技多不压身。而…

php如何实现验证码

验证码在表单实现越来越多了&#xff0c;但是用js的写的验证码&#xff0c;总觉得不方便&#xff0c;所以学习了下php实现的验证码。好吧&#xff0c;其实是没有事情干&#xff0c;但是又不想浪费时间&#xff0c;所以学习了下php实现验证码。正所谓&#xff0c;技多不压身。而…

基于matlab使用自校准来适应阵列不确定性(附源码)

一、前言 此示例显示了基于约束优化过程的自校准过程。利用机会来源同时估计阵列形状的不确定性和来源方向。此示例需要优化工具箱。 理论上&#xff0c;可以设计一个完美的均匀线性阵列&#xff08;ULA&#xff09;来执行各种处理&#xff0c;例如波束成形或到达方向估计。通常…

软考知识点汇总

本篇文章为22年上半年软件设计师备考笔记 个人总结笔记&#xff0c;如有错误望包涵指正 计算机组成和结构 海明校验码 n个数据位&#xff0c;设k个校验位 2 k > n k 1 2^{k}>nk1 2k>nk1 整个编码系统中任意两个码字的最小距离就是该编码系统的码距。为了使一个系…

程序员必备软技能之科技趋势(一)

一、知识点 语音公司&#xff1a;搜狗、科大讯飞 美的&#xff1a;收购了全球领先的机器臂公司。 BTC、ETH、不支持ICO BTC跌其他货币也会跌&#xff0c;其他货币跌BTC不一定跌。心目中的第一货币。 商业机器人将逐渐代替工业机器人。&#xff08;泡茶、叠衣&#xff09; …

工作人员必备的计算机知识,工作必备计算机技巧知识

随着我们对电脑的使用&#xff0c;各式各样的软件应用被安装到电脑上&#xff0c;电脑开机时&#xff0c;你可能会感觉到电脑开机速度会变慢&#xff0c;其实这是一个很常见的问题。下面就让小编带你去看看工作必备计算机技巧知识吧&#xff0c;希望能帮助到大家! 电脑技巧|关闭…