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

日常跳转:

  • 导入
    • 单个短视频
      • 获取视频的信息
      • 通过m3u8文件地址下载视频
      • 源码及效果
    • 番剧剧集
      • 获取视频的信息
      • 番剧剧集链接
      • 源码及效果

导入

前段时间我已经将B站的爬取方法做了一个总结:Python爬虫:哔哩哔哩(bilibili)视频下载。

这一次,我将继续分享 AcFun 视频网站的解析,其实相对于B站,A站的反爬机制更为简单:


单个短视频

获取视频的信息

为了能够方便的解析与说明,就肯定会拿一个例子来才好的哇:

【仙女UP特辑】AcFun Family Party ——成都站(今天又是 lsp 的一天呢~~)

直接在浏览器端打开并抓包该链接发现,在 XHR 的数据下,第一条(又或者某一次)的请求就加载了视频的真实请求链接:
虽然本身仅仅是一个 m3u8 文件,不过我们还是有办法处理的,我们在此之前先必须要找到该文件的亲亲贵是从哪里发出来的,又或者能够在哪里找到这个链接。

在找遍了 XHR 数据无果后,我决定去看一看网页源码:
当我用 m3u8 文件的请求链接在网页源码中搜索后发现,链接就出现在源码中:

因为在源码中是以 JSON 数据存放的:

所以我们需要将数据格式化,方便我们进行数据提取:

虽然我将该数据格式化以后发现,有一个字段的值居然也是一个 JSON 数据的格式,所以我们再对第二层的 JSON 数据进行格式化后可以看到以下信息:

对于未登录时的状态,即使网页端不能直接播放,但是 “ 后台 ” 早已经给我们准备好了播放链接(B站则是加载当前账户或着未登录时能观看的最大清晰度),所以我们可以在未登陆的情况下 白嫖 超高清资源~~

class m3u8_url():def __init__(self, f_url):self.url = f_urldef get_m3u8(self):global flag, qua, rel_pathhtml = requests.get(self.url, headers=headers).textfirst_json = json.loads(re.findall('window.pageInfo = window.*? = (.*?)};', html)[0] + '}', strict=False)name = first_json['title'].strip().replace("|",'')video_info = json.loads(first_json['currentVideoInfo']['ksPlayJson'], strict=False)['adaptationSet'][0]['representation']

为了后续能够选择清晰度,所以我还进行了清晰度的爬取:

for quality in video_info:  # 清晰度num += 1Label[num] = quality['qualityLabel']
print(Label)
choice = int(input("请选择清晰度: "))

通过m3u8文件地址下载视频

到此,我们已经可以拿到视频的 m3u8 文件的地址,那么现在就来开始解决之前遗留的一个小问题:如何通过 m3u8 文件下载视频?

首先,我们拿到一个 m3u8 文件来作为案例:
为了方便,在这里我手动的写了一个 m3u8 文件来作为例子。

我们知道,在 m3u8 文件中的视频链接都是 .ts 的分段格式,所以我们必须要先想办法将所有的 .ts 链接都拿出来,并且加上前缀,拼装成视频的真实完整的链接:(在这里假设视频原前缀为 https://www.acfun.cn/)

urls=[]  # 用于保存视频的分段链接
def get_ts_urls():with open('123.m3u8',"r") as file:lines = file.readlines()for line in lines:if '.ts' in line:print("https://www.acfun.cn/"+line)

通过以上方法,我们就可以通过 m3u8 文件来获取每一段的视频链接了,接下来,我们再将下载的功能进行完善:

下载的基本思路还是和我以前的一篇文章的思路一样:Python爬虫:用最普通的方法爬取ts文件并合成为mp4格式

class Download(): urls = []  # 用于保存视频的分段链接def __init__(self, name, m3u8_url, path):''':param name: 视频名:param m3u8_url: 视频的 m3u8文件 地址:param path: 下载地址'''self.video_name = nameself.path = pathself.f_url = str(m3u8_url).split('hls/')[0] + 'hls/'with open(self.path + '/{}.m3u8'.format(self.video_name), 'wb')as f:f.write(requests.get(m3u8_url, headers={'user-agent': 'Chrome/84.0.4147.135'}).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 '.ts' in line:self.urls.append(self.f_url + line.replace('\n', ''))def start_download(self):self.get_ts_urls()for url in tqdm(self.urls, desc="正在下载 {} ".format(self.video_name)):movie = requests.get(url, headers={'user-agent': 'Chrome/84.0.4147.135'})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))

代码注解:

  • 1、为了最后得到的只有视频,所以在视频下载完后,自动的将当前视频的 m3u8 文件进行了删除操作。
  • 2、line.replace('\n', '') 的原因:读取到的 m3u8 文件的每一行结尾都含有一个 " \n "

源码及效果

终于,到现在我们已经可以整合代码并运行看一看了:

import os
import re
import json
import requests
from tqdm import tqdmpath = './'headers = {'referer': 'https://www.acfun.cn/','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83'
}class m3u8_url():def __init__(self, f_url):self.url = f_urldef get_m3u8(self):global flag, qua, rel_pathhtml = requests.get(self.url, headers=headers).textfirst_json = json.loads(re.findall('window.pageInfo = window.videoInfo = (.*?)};', html)[0] + '}', strict=False)name = first_json['title'].strip().replace("|",'')video_info = json.loads(first_json['currentVideoInfo']['ksPlayJson'], strict=False)['adaptationSet'][0]['representation']Label = {}num = 0for quality in video_info:  # 清晰度num += 1Label[num] = quality['qualityLabel']print(Label)choice = int(input("请选择清晰度: "))Download(name + '[{}]'.format(Label[choice]), video_info[choice - 1]['url'], path).start_download()class Download():urls = []def __init__(self, name, m3u8_url, path):''':param name: 视频名:param m3u8_url: 视频的 m3u8文件 地址:param path: 下载地址'''self.video_name = nameself.path = pathself.f_url = str(m3u8_url).split('hls/')[0] + 'hls/'with open(self.path + '/{}.m3u8'.format(self.video_name), 'wb')as f:f.write(requests.get(m3u8_url, headers={'user-agent': 'Chrome/84.0.4147.135'}).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 '.ts' in line:self.urls.append(self.f_url + line.replace('\n', ''))def start_download(self):self.get_ts_urls()for url in tqdm(self.urls, desc="正在下载 {} ".format(self.video_name)):movie = requests.get(url, headers={'user-agent': 'Chrome/84.0.4147.135'})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))url1 = input("输入地址: ")
m3u8_url(url1).get_m3u8()

效果:


哦豁~ 起飞~~


番剧剧集

获取视频的信息

既然要从番剧入手,那肯定就还是拿一个例子来说明吧:

租借女友 (又是 lsp 的呢~~)

针对这部番剧,我们直接从单个视频解析方式来获取经验 -----> 直接从网页源码开始:

果然也在源码中找到了与单个视频类似的 JSON 数据,我们继续将这些数据进行格式化:

结果视频的 存放方式存放的字段 和单个视频 一摸一样,为了减少最后的代码量,我们可以将两种方式都适配到一个类中:

class m3u8_url():def __init__(self, f_url, name=""):''':param f_url: 当前视频的链接:param name:  番剧名,默认为空'''self.url = f_urlself.name = namedef get_m3u8(self):global flag, qua, rel_pathhtml = requests.get(self.url,  headers=headers).textfirst_json = json.loads(re.findall('window.pageInfo = window.*? = (.*?)};', html)[0] + '}', strict=False)if self.name == '':name = first_json['title'].strip().replace("|",'')else:name = self.namerel_path = path + first_json['bangumiTitle'].strip()if os.path.exists(rel_path):passelse:os.makedirs(rel_path)video_info = json.loads(first_json['currentVideoInfo']['ksPlayJson'], strict=False)['adaptationSet'][0]['representation']Label = {}num = 0for quality in video_info:  # 清晰度num += 1Label[num] = quality['qualityLabel']if flag:print(Label)choice = int(input("请选择清晰度: "))flag = Falsequa = choiceDownload(name + '[{}]'.format(Label[choice]), video_info[choice - 1]['url'], path).start_download()else:Download(name + '[{}]'.format(Label[qua]), video_info[qua - 1]['url'], rel_path).start_download()

代码注解:

  • flag :用于判断是否已经选择了下载时的清晰度。
  • qua : 保存选择的清晰度。
  • rel_path :更改番剧下载的位置(番剧名的文件夹下)。
  • first_json = json.loads(re.findall(‘window.pageInfo = window.? = (.?)};’, html)[0] + ‘}’, strict=False) :更改视频信息的匹配正则表达式,可以同时用来匹配单个视频和番剧视频。

知道了某一集怎么下载,总不可能要每一集都要去手动输入链接吧!!!遇到只有几集的番剧还好,要是遇到这样的:

你来???


番剧剧集链接

同样的,我们还是从网页源码出发:

虽然我们能在源码中找到番剧的所有信息,但是,并不是所有的都是我们需要的,我们还要先去看看哪些信息是我们必须要拿到的:
当我点击第二集时,浏览器地址栏的地址发生了变化:

https://www.acfun.cn/bangumi/aa6002917_36188_1740687

我们很容易的就可以发现:

  • https://www.acfun.cn/bangumi/aa6002917 :番剧的主页链接。
  • 36188 :一串不知道有什么用的数字,不过我发现它并没有什么用,都是固定的:

举几个例子:
租借女友 :第2话 前女友和女友:https://www.acfun.cn/bangumi/aa6002917_36188_1740687
租借女友 :第3话 海和女友:https://www.acfun.cn/bangumi/aa6002917_36188_1741409
镇魂街 :第2话:https://www.acfun.cn/bangumi/aa5020166_36188_232386

同样的点回第一集时也可以看到第一集的链接也可以写成:
镇魂街 :第1话:https://www.acfun.cn/bangumi/aa5020166_36188_232383
租借女友 :第1话 租借女友:https://www.acfun.cn/bangumi/aa6002917_36188_1739760

  • 1740687 :每一集的 ID ,在源码中以 itemId 字段保存。

于是,我们就可以写出获取每一集视频链接的代码:

class Pan_drama():def __init__(self, f_url):''':param f_url: 视频主页的链接'''self.aa = len(str(f_url).split('/')[-1])if self.aa == 7:self.url = f_urlelif self.aa > 7:self.url = str(f_url).split('_')[0]def get_info(self):video_info = {}html = requests.get(self.url, headers=headers).textall_item = json.loads(re.findall('window.bangumiList = (.*?);', html)[0])['items']for item in tqdm(all_item, desc="正在准备番剧"):video_info[item['episodeName'] + '-' + item['title']] = self.url + '_36188_' + str(item['itemId'])for name in video_info.keys():m3u8_url(video_info[name],name).get_m3u8()

代码注解:

  • self.aa :为了更好的适应性,简单的解决一下,传入某一集的链接,但是可以下载全番剧的情况。

源码及效果

全部源码:

import os
import re
import json
import requests
from tqdm import tqdmpath = './'headers = {'referer': 'https://www.acfun.cn/','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83'
}flag = True
qua = 0class m3u8_url():def __init__(self, f_url, name=""):''':param f_url: 当前视频的链接:param name:  番剧名,默认为空'''self.url = f_urlself.name = namedef get_m3u8(self):global flag, qua, rel_pathhtml = requests.get(self.url, headers=headers).textfirst_json = json.loads(re.findall('window.pageInfo = window.*? = (.*?)};', html)[0] + '}', strict=False)if self.name == '':name = first_json['title'].strip().replace("|", '')rel_path=pathelse:name = self.namerel_path = path + first_json['bangumiTitle'].strip()if os.path.exists(rel_path):passelse:os.makedirs(rel_path)video_info = json.loads(first_json['currentVideoInfo']['ksPlayJson'], strict=False)['adaptationSet'][0]['representation']Label = {}num = 0for quality in video_info:  # 清晰度num += 1Label[num] = quality['qualityLabel']if flag:print(Label)choice = int(input("请选择清晰度: "))flag = Falsequa = choiceDownload(name + '[{}]'.format(Label[choice]), video_info[choice - 1]['url'], rel_path).start_download()else:Download(name + '[{}]'.format(Label[qua]), video_info[qua - 1]['url'], rel_path).start_download()class Pan_drama():def __init__(self, f_url):''':param f_url: 视频主页的链接'''self.aa = len(str(f_url).split('/')[-1])if self.aa == 7:self.url = f_urlelif self.aa > 7:self.url = str(f_url).split('_')[0]def get_info(self):video_info = {}html = requests.get(self.url, headers=headers).textall_item = json.loads(re.findall('window.bangumiList = (.*?);', html)[0])['items']for item in tqdm(all_item, desc="正在准备番剧"):video_info[item['episodeName'] + '-' + item['title']] = self.url + '_36188_' + str(item['itemId'])for name in video_info.keys():m3u8_url(video_info[name],name).get_m3u8()class Download():urls = []def __init__(self, name, m3u8_url, path):''':param name: 视频名:param m3u8_url: 视频的 m3u8文件 地址:param path: 下载地址'''self.video_name = nameself.path = pathself.f_url = str(m3u8_url).split('hls/')[0] + 'hls/'with open(self.path + '/{}.m3u8'.format(self.video_name), 'wb')as f:f.write(requests.get(m3u8_url, headers={'user-agent': 'Chrome/84.0.4147.135'}).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 '.ts' in line:self.urls.append(self.f_url + line.replace('\n', ''))def start_download(self):self.get_ts_urls()for url in tqdm(self.urls, desc="正在下载 {} ".format(self.video_name)):movie = requests.get(url, headers={'user-agent': 'Chrome/84.0.4147.135'})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))url1 = input("输入地址: ")
if url1.split('/')[3] == 'v':m3u8_url(url1).get_m3u8()
elif url1.split('/')[3] == 'bangumi':Pan_drama(url1).get_info()

效果示例:


(因为考虑到万一要被拉黑的问题,那不就 gg 了,所以我没加入多线程,有需要可以直行尝试尝试~~~)

Python爬虫:AcFun弹幕视频网相关推荐

  1. android acfun,AcFun弹幕视频网

    AcFun弹幕视频网它是一个二维动画平台,不仅在软件中有特殊内容,还能看到最新系列的动画戏剧,大量的动物和动物视频剪辑带给你无限的欢乐,在那里你可以看到你想看到的东西. 软件简介 相聚A站,回顾经典- ...

  2. Python爬虫:AcFun弹幕视频网!太清晰了!

    单个短视频 获取视频的信息 为了能够方便的解析与说明,就肯定会拿一个例子来才好的哇: [仙女UP特辑]AcFun Family Party --成都站(今天又是 lsp 的一天呢~~) 直接在浏览器端 ...

  3. 怎么用Python写出随时间变化的字_Python爬虫实战,AcFun弹幕视频网 - 长情且温柔

    ​ CSDN个人主页: 高智商白痴原文地址: 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更 ...

  4. ACFUN弹幕视频网播放器弹幕JSON文件参数浅析

    ACFUN目前的播放器的弹幕文件是由JSON为载体存储,为了本地编辑JSON便于查询记下此篇.查看json文件传送门(弹幕池通过什么开发人员工具就可以看到):http://comment.acfun. ...

  5. java web弹幕_JavaWeb - AcFun弹幕视频网 - 认真你就输啦 (?ω?)ノ- ( ゜- ゜)つロ

    001-Servlet-学习内容介绍 002-IDEA-IDEA的下载与安装 003-IDEA-IDEA创建Java项目 004-IDEA-IDEA的基本设置 005-HTTP-浏览器和服务器的交互流 ...

  6. Python爬虫:短视频平台无水印下载(上)

    本博客所写爬取规则最近更新日期为:2020/12/11 新增:西瓜视频 皮皮虾的解析规则已经失效,新版规则已更新 提醒:转载请标明作者和原文链接!!! CSDN个人主页: 高智商白痴 原文地址: ht ...

  7. Python爬虫:短视频平台无水印下载!强不强?

    导入: 虽然目前有些软件还没适配,但是,我发了 Blink 后有一写人留言或者私信找我要源码,不过我还在增加适配的软件,所以还没有时间写这篇博客,今天呢,就先把我目前适配了的代码拿出来,后续还会继续适 ...

  8. python爬虫爬猎聘网获取多条职责描述中有Linux需求的招聘信息

    python爬虫爬猎聘网获取多条职责描述中有Linux需求的招聘信息 下列是我爬虫的作业 摘 要 随着现代化社会的飞速发展,网络上巨大信息量的获取给用户带来了许多的麻烦.由于工作和生活节奏的需求,人们 ...

  9. Python爬虫(6):煎蛋网全站妹子图爬虫

    Python爬虫(6):煎蛋网全站妹子图爬虫 上一篇文章中我们抓取了豆瓣图书的数据,如果大家运行成功,并且看到文件夹下的 txt 文件了.是不是有一种刚接触编程,第一次输出Hello world!时的 ...

最新文章

  1. 转载--【笔记】Asp.Net构架(Http请求处理流程)
  2. 电脑音频服务未运行怎么解决_电脑故障维修技巧教程:新手必看的修电脑技巧!...
  3. 记录下最近使用到的sql语句
  4. php form表单属性,HTML5 表单属性
  5. SIP Trunk / SIP 中继服务
  6. SQL 语句 - Select(2): 指定表中的字段
  7. SpringMCV结构
  8. oracle数据库赋权_(转)Oracle数据库如何授权收费(Database Licensing)
  9. 树莓派安装smbus_树莓派安装wiringPi,BCM2835,以及python的RPI.GPIO
  10. 基于matlab的gmsk,基于MATLAB的GMSK仿真分析-移动通信系统三级项目报告
  11. Android 实现计时器功能,Android计时器的三种实现方式(Chronometer、Timer、handler)...
  12. 安利App介绍及下载(含二维码)
  13. TypeScript02 方法特性【参数种类、参数个数】、generate方法、析构表达式、箭头表达式、循环...
  14. 2022.11.12 英语背诵
  15. [网络安全自学篇] 七十一.深信服分享之外部威胁防护和勒索病毒对抗
  16. 关于2进制与十六进制的转换;C语言
  17. 一种基于Android、iOS系统的移动端车牌识别方法,实现手机拍照识别车牌
  18. 冯米塞斯应力计算的各种形式
  19. k均值聚类算法考试例题_k means聚类算法实例
  20. Flask操作指南(超级详细)

热门文章

  1. Layui 引入jQuery.Cookie插件
  2. 互联网现象背后心理学:为何“蠢萌”比“高冷”更容易火
  3. 如何提高自己博客的人气
  4. Pr进阶:时间重映射与时间插值
  5. 充电助手---安卓手机充电专业软件
  6. php 模拟登陆爬取_PHP模拟登录并获取数据
  7. 17.Cocos跑酷游戏——04添加障碍物
  8. 恐怖游戏需要优秀的剧情吗?聊聊《港诡实录》的剧情架构
  9. 百度地图 点maker在区域判断(圆Circle,多边形polygon,矩形rectangle,线line上)
  10. DjVu转PDG的方法与步骤