关于puppeteer:使用puppeteer提取网页中的视频地址

21次阅读

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

我的项目需要是提供一个接口通过输出一个网页地址,抓取网页中的视频地址!例如关上一个 网页地址

须要将网页中的视频地址提取进去。作为前端开发人员的惯性思维,看到这个网页的 html 构造,这个不是很简略嘛,一行代码就搞定:document.querySelector('video source').src

嘻嘻,功败垂成,筹备摸鱼~

等等!这个只是在浏览器的控制台中拿到了视频的地址,然而如何转化成为提供一个接口,通过接口返回这个地址呢?初步猜测,应用 get 申请获取网页的 html,而后剖析 dom 构造,解析出 video 标签。

谬误尝试

间接通过 get 申请页面的地址获取到的内容并不是咱们在浏览器所看到的内容。目前的网页大多都是动静网页,即页面最终出现的内容是通过加载 js 后执行脚本动静拼接的,因而页面中的 video 标签并不是间接从服务端拼接好的。

浏览器加载网页的申请截图,没有间接返回 dom 构造,全是加载一堆 js 和 css 文件

并且!很多网站都做了防爬措施,间接申请页面的地址会返回一个两头页面,例如抖音和微博的视频详情页面,间接申请会返回一个相似于认证的页面,初步剖析了这个页面,这个直达页面应该是判断有没有相应 cookie 的信息,如果没有相应的信息,就会给浏览器设置 cookie 之类的信息,最初会走一个 window.location.reload(); 让页面刷新一次(微博会间接走到一个 Sina Visitor System 的页面不会间接跳转到详情页面)。这个脚本在浏览器中会主动执行,因而会从新加载一次,看到最终的详情页面。然而 get 申请仅仅是获取到了直达页面的 html,并没有走到真正的详情页面。

抖音详情页面 get 申请
https://www.douyin.com/video/7020764246476590339

微博详情页面 get 申请
https://weibo.com/tv/show/1034:4699424946061376?mid=4699425262272582

哎呀!连最终的网页信息都拿不到,怎么可能拿到页面视频地址呢?这下可不能欢快的摸鱼了

通过调研后决定采纳 Node.js + Puppeteer来实现这个性能,本文次要记录我的项目的实现思路和开发部署中遇到的难点及其解决方案,仅供学习参考。

Puppeteer 是 Chrome 开发团队在 2017 年公布的一个 Node.js 包,用来模仿 Chrome 浏览器的运行. 次要通过 Puppeteer 运行 Chromium 加载网页实现剖析页面 dom 获取 video 标签,实现视频地址抓取

参考资料:

Puppeteer 中文文档

https://github.com/puppeteer/puppeteer

开发环境(Windows)

决定应用 puppeteerjs 后外面在 windows 环境下进行开发,
windows 环境为Node v12.16.2, puppeteerjs v2.1.1

puppeteerjs的最新版为 13.1.1。然而puppeteerjs v3.0 版本及以上须要 Node v10 及以上, 因为我本地的开发环境 Node 为 v12, 服务器上的 Node 为 v8,因而本地开发没问题,然而服务器上始终部署不胜利,且服务器下面有很多其余我的项目都是基于 node v8 版本的,因而服务器上的 node 版本不宜降级。为放弃和服务器版本统一,windows 环境下的 puppeteerjs 也应用2.1.1 版本;

间接上代码
server2.js

const puppeteer = require('puppeteer');

async function getVideoUrl () {const browser = await puppeteer.launch();// 关上浏览器
    const page = await browser.newPage();
    await page.emulate(puppeteer.devices['iPhone 6'])
    await page.goto('https://www.douyin.com/video/7020764246476590339'); // 跳转到指定页面
    await page.waitFor(2000)  // 延时 2s 加载页面 puppeteer2.1.1 应用 waitFor ^13.0.1 以上应用 waitForTimeout  
    const pageHtml = await page.content(); // 获取页面 html Gets the full HTML contents of the page, including the doctype.
    console.log(pageHtml);
}
getVideoUrl()

执行node server2.js,输入的后果就是详情页面的 html 代码了

puppeteer.launch中的 headless 默认 true, 如果设置为false, 会关上一个Chromium 加载网页, 并且能间接调试网页!

await puppeteer.launch({headless: false, // 是否无头浏览});

拿到了 html 代码咱们怎么进一步获取 video 标签呢?

间接应用 dom 剖析视频标签

puppeteer给咱们提供了相应的 api,因为浏览器渲染 dom 曾经申请接口须要工夫,因为第一工夫咱们拿到都网页代码也不是残缺的,因而咱们须要加延时。

await page.waitForTimeout(2000); // 延时 2s 加载页面 puppeteer2.1.1 应用 waitFor ^13.0.1 以上应用 waitForTimeout  
const videoSrc = await page.$eval('video source', (el) => {
    let src = '';
    if (el && el.src) {src = el.src;}
    return src;
});

拦挡接口

局部页面是间接通过申请接口获取到的视频地址,对于这种网页咱们能够应用下面的办法,等页面加载结束后剖析 dom,然而查阅 puppeteer 的文档时发现能够间接拦挡接口,获取接口的返回信息,
因而,如果咱们针对指定的详情,晓得其申请规定,能够间接通过接口响应获取相应的数据。

// 注册响应监听事件
page.on('response', async (response) => {if (response.ok()) {const request = response.request();
        const reqUrl = request.url();
        if (reqUrl.indexOf('/api/getHttpVideoInfo.do') > -1) { // 拦挡 /api/getHttpVideoInfo.do 接口
            const respData = await response.json();
            const video = respData.video;
            if (video && video.validChapterNum > 0){const currentChapter = video[`chapters${video.validChapterNum}`];
                if (currentChapter && currentChapter.length > 0 && currentChapter[0] && currentChapter[0].url) {resolve(currentChapter[0].url)
                }
            }
        }
    }
})

这种形式是指针对有明确接口,切能拿到相应的申请参数的页面应用!

增加前端页面欠缺接口

残缺的代码已提交到 github,链接在前面给出

关上本地网页拜访:localhost:18000

服务端部署(Linux)

服务端环境为 linux 环境,零碎为 CentOS-8,Node.js 版本为 v8.11.3,Linux 环境和 windows 环境部署的时候有点区别,特地是装置 puppeteer 时须要留神
装置 puppeteer 时会报以下谬误

ERROR: Failed to download Chromium r722234! Set "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" env variable to skip download.
Error: EACCES: permission denied, mkdir '/opt/video-url-analysis/node_modules/puppeteer/.local-chromium'

因为装置 puppeteer 时会装置Chromium,须要权限,因而在 linux 环境下应用以下命令装置

npm install puppeteer@2.1.1 --unsafe-perm=true --allow-root

装置结束后启动程序,胜利运行并抓取网页视频!

其余

linux 下启动浏览器 headless须要设置为 true, 增加args 参数

const browser = await puppeteer.launch({
    headless: true, // 是否启用无头浏览 默认为 true
    args: [
        '--no-sandbox',
        '--disable-setuid-sandbox'
    ]
});

其余异样谬误:
1.Failed to launch the browser process

Failed to launch the browser process
...
error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory

应该是短少 chromium,手动装置 chromium 后解决问题

sudo yum install -y chromium

或者(我这边应用后者解决了问题)

sudo yum -y install libXScrnSaver-1.2.2-6.1.el7.x86_64

2. 应用 yum 装置软件依赖出错,始终提醒找不到软件包

[root@localhost video-url-analysis]# sudo yum install -y chromium
上次元数据过期查看:0:00:47 前,执行于 2022 年 01 月 20 日 星期四 21 时 35 分 27 秒。未找到匹配的参数: chromium
谬误:没有任何匹配: chromium

起因是 CentOS 8 没有装置 epel 源的问题, 装置 epel 源后问题解决:
yum install epel-release

代码

残缺代码已上传 https://github.com/zhaosheng808/video-grab 欢送 star,仅供学习参考, 切勿用于非法路径

1. 装置依赖

npm install

2. 本地开发

npm run dev

关上本地网页拜访:localhost:18000

总结

windows 环境下开发比较顺利,因为自己是前端切图仔,服务器接触较少,所以 linux 服务端部署遇到的问题较多,因而记录一下解决问题的过程,不便后续开发者遇到问题可能顺利解决。
服务端常识有所欠缺,如有有余,还请海涵!

正文完
 0