关于puppeteer:使用-puppeteer-nodejs-爬取喜欢的动漫资源

38次阅读

共计 3155 个字符,预计需要花费 8 分钟才能阅读完成。

起源

  • 最近忽然想尝试剪视频,所以就想先从动漫开始,二次元搞起来,剪视频就必须须要原视频,怎么找到这些资源呢,知乎一搜一大把
  • 我常常会上六 DM 外面去看动漫, 外面的动漫清晰度也还能够,所以就想怎么写个爬虫间接把喜爱的动漫下载下来,毕竟是干前端的,手动下载有点丢人把 😄😄😄

最终成果



下载后的文件名不是.mp4 怎么解决

比如说我下载的这个龙猫就是啥 yum 格局的,我间接后缀名改成.mp4 搞定,如果还不行,就上个格局工厂 应该就好了


作者在写这篇文章的技能和环境

  • 前端略懂一二
  • nodejs 无所不通
  • window 零碎
  • puppeteer 版本: 14.3.0
  • node 版本: 16.1.0

开始剖析网站, 轻易搜一个喜爱的动漫

介绍页

轻易点击一个播放地址,F12 搞起来,剖析页面

能够,这个网站还是会玩的,调试工具开起来就给我始终 debugger

如何跳过 debugger 死循环

这种形式能够不便跳过死循环,并且咱们还能够持续调试

找到页面播放地址

这个网站还是很简略的,间接把资源地址丢到 iframe 外面而已,难度升高了,怪不得不给他人调试,😄😄

剖析播放地址由来

思路 1:通过接口申请剖析,是否存在共通点

通过抓包,发现第一集和第二集的播放资源门路没有共同性可言,放弃 o(╥﹏╥)o

思路 2:间接看播放器的源码逻辑,找到 url 的拼接逻辑

找出播放器源码,间接通过调试工具找到所有的 js 文件,而后轻易看看

剖析播放器源码

读取播放器源码发现,这个网站会在页面外面存入一个全局变量

全局变量 player_aaaa
会做赋值存储,而后会引入一个 js 文件,文件名:/static/player/parse.js
关上调试工具,找到 /static/player/parse.js 文件,
/static/player/parse.js 文件内容
  • 浏览器控制台输出:MacPlayer.Parse + MacPlayer.PlayUrl

    因为播放器的源码是一个自执行函数,而后咱们又看到这个 parse.js 文件外面的资源拼接形式,所以咱们能够在浏览器的控制台外面间接把这个资源给拼出来

右键保留?

把下面的地址放到浏览器外面拜访,发现就是咱们想下载的资源了,到了这一步骤,咱们就能够右键保留了,当然作为一名合格的前端,咱们怎么可能会去右键保留呢,接下来咱们就筹备上大杀器,puppeteer 配合 nodejs 来帮咱们实现主动下载
资源 demo

如何做自动化?
  • 通过下面的连贯,会进入到一个解析页面,因为咱们要做成主动下载的,必须要找到视频源连贯,否则不行,o(╥﹏╥)o
  • 查找元素页面,发现了最终的资源地址
  • 最终的资源地址

应用 puppeteer 解析页面,获取到视频资源地址,而后应用 nodejs 主动下载视频

思路 1:遍历出播放列表,而后开始一个工作,顺次关上页面,找到资源地址,而后收集到所有的播放资源地址,应用 nodejs 下载到本地,

为啥不必下面那个思路,因为那个思路我把代码写完,测试了一下,发现他的服务器扛不住哈,所以还是保险点,一次一个操作

思路 2:应用 puppetee 主动触发右键下载,并保留到咱们想要下载的中央(目前没有尝试这个办法)

思路 3:遍历出播放列表,而后开始一个工作,从第一个开始,关上页面,找到资源地址,应用 nodejs 下载到本地,下载实现,开始下一个就这样

思路 3 难点剖析

pupeteer 如何获取元素的属性,别问我,反正我不懂,堆栈溢出大佬通知我的
  • 堆栈溢出的答案

// 获取单个
await page.evaluate('document.querySelector("span.styleNumber").getAttribute("data-Color")')
// 获取多个
const attr = await page.$$eval("span.styleNumber", el => el.map(x => x.getAttribute("data-Color")));
nodejs 下载远端视频,并显示进度
const fs = require('fs');
const https = require('https')
// 我的 demo 应用的是 axios 来下载
const axiosRequest = require('./utils/request');
// 这是一个 axios 实例
axiosRequest.get('https://media.w3.org/2010/05/sintel/trailer.mp4', {responseType: 'stream'}).then(response => {
// 返回头外面的 content-length 字段,会通知咱们这个视频有多大
//  获取视频总长度 byte 为单位
const totalLength = response.headers['content-length']
// 以后数据的总长度
let totalChunkLength = 0
// 以后读取的流
const readSteam = response.data
// 读取流会触发的事件
readSteam.on('data', (chunk) => {
totalChunkLength += chunk.length
console.log('数据传输中,以后进度 ==>', ((totalChunkLength / totalLength) * 100).toFixed(2) + '%')
  });
// 读取实现的工夫
readSteam.on('end', (chunk) => {console.log('获取远端数据结束')
  });
// 读取谬误会触发的事件
readSteam.on('error', (err) => {console.log('获取远端数据结束,产生了谬误, 错误信息 ==>', err)
  });
// 写入本地的文件名
const fileName = 67.mp4
// 调用 nodejs 写入文件办法
const writeFile = readSteam.pipe(fs.createWriteStream(fileName))
// 写入实现事件
writeFile.on("finish", () => {writeFile.close();
console.log("祝贺大哥,本地数据写入实现");
    });
// 写入谬误触发的事件
writeFile.on("error", (err) => {console.log("不好意思,写入本地文件产生异样,错误信息 ==>", err);
  });
});
//axios 代码如下
const axios = require('axios')

// 创立 axios 实例
const service = axios.create({
 baseURL: '', // api 的 base_url
 // 永不凋零,真男人 就是这么长久 😄😄
 timeout: 90000000 // 申请超时工夫
})

// request 拦截器
service.interceptors.request.use(
 config => {return config},
 error => {
   // Do something with request error
   console.log(error) // for debug
   Promise.reject(error)
 }
)

// 响应拦截器
service.interceptors.response.use(
 response => {return response},
 error => {return Promise.reject(error)
 }
)


module.exports = service

残缺代码

残缺代码

免责申明

  • 首先 非常感谢这个网站让我这个老二次元可能找到喜爱的片源 😄😄😄
  • 本我的项目只是学习应用,无心对此网站进行爬虫等操作
  • 心愿想用的同学本人玩玩就行,树大招风
  • 侵权请分割,立马删除
  • 就这些吧

参考资料

破解视频的另一个思路
puppeterr 获取元素属性
puppeterr 下载文件

正文完
 0