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

须要将网页中的视频地址提取进去。作为前端开发人员的惯性思维,看到这个网页的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服务端部署遇到的问题较多,因而记录一下解决问题的过程,不便后续开发者遇到问题可能顺利解决。
服务端常识有所欠缺,如有有余,还请海涵!