需要将网页中的视频地址提取出来。作为前端开发人员的惯性思维,看到这个网页的html结构,这个不是很简单嘛,一行代码就搞定:document.querySelector('videosource').src
嘻嘻,大功告成,准备摸鱼~
等等!这个只是在浏览器的控制台中拿到了视频的地址,但是如何转化成为提供一个接口,通过接口返回这个地址呢?初步猜想,使用get请求获取网页的html,然后分析dom结构,解析出video标签。
直接通过get请求页面的地址获取到的内容并不是我们在浏览器所看到的内容。目前的网页大多都是动态网页,即页面最终呈现的内容是通过加载js后执行脚本动态拼接的,因此页面中的video标签并不是直接从服务端拼接好的。
浏览器加载网页的请求截图,没有直接返回dom结构,全是加载一堆js和css文件
并且!很多网站都做了防爬措施,直接请求页面的地址会返回一个中间页面,例如抖音和微博的视频详情页面,直接请求会返回一个类似于认证的页面,初步分析了这个页面,这个中转页面应该是判断有没有相应cookie的信息,如果没有相应的信息,就会给浏览器设置cookie之类的信息,最后会走一个window.location.reload();让页面刷新一次(微博会直接走到一个SinaVisitorSystem的页面不会直接跳转到详情页面)。这个脚本在浏览器中会自动执行,因此会重新加载一次,看到最终的详情页面。但是get请求仅仅是获取到了中转页面的html,并没有走到真正的详情页面。
哎呀!连最终的网页信息都拿不到,怎么可能拿到页面视频地址呢?这下可不能愉快的摸鱼了
通过调研后决定采用Node.js+Puppeteer来实现这个功能,本文主要记录项目的实现思路和开发部署中遇到的难点及其解决方案,仅供学习参考。
参考资料:
决定使用puppeteerjs后里面在windows环境下进行开发,windows环境为Nodev12.16.2,puppeteerjsv2.1.1
puppeteerjs的最新版为13.1.1。但是puppeteerjsv3.0版本及以上需要Nodev10及以上,因为我本地的开发环境Node为v12,服务器上的Node为v8,因此本地开发没问题,但是服务器上一直部署不成功,且服务器上面有很多其他项目都是基于nodev8版本的,因此服务器上的node版本不宜升级。为保持和服务器版本一致,windows环境下的puppeteerjs也使用2.1.1版本;
直接上代码server2.js
puppeteer.launch中的headless默认true,如果设置为false,会打开一个Chromium加载网页,并且能直接调试网页!
awaitpuppeteer.launch({headless:false,//是否无头浏览});
拿到了html代码我们怎么进一步获取video标签呢?
awaitpage.waitForTimeout(2000);//延时2s加载页面puppeteer2.1.1使用waitFor^13.0.1以上使用waitForTimeoutconstvideoSrc=awaitpage.$eval('videosource',(el)=>{letsrc='';if(el&&el.src){src=el.src;}returnsrc;});拦截接口部分页面是直接通过请求接口获取到的视频地址,对于这种网页我们可以使用上面的方法,等页面加载完毕后分析dom,但是查阅puppeteer的文档时发现可以直接拦截接口,获取接口的返回信息,因此,如果我们针对指定的详情,知道其请求规则,可以直接通过接口响应获取相应的数据。
//注册响应监听事件page.on('response',async(response)=>{if(response.ok()){constrequest=response.request();constreqUrl=request.url();if(reqUrl.indexOf('/api/getHttpVideoInfo.do')>-1){//拦截/api/getHttpVideoInfo.do接口constrespData=awaitresponse.json();constvideo=respData.video;if(video&&video.validChapterNum>0){constcurrentChapter=video[`chapters${video.validChapterNum}`];if(currentChapter&¤tChapter.length>0&¤tChapter[0]&¤tChapter[0].url){resolve(currentChapter[0].url)}}}}})这种方式是指针对有明确接口,切能拿到相应的请求参数的页面使用!
完整的代码已提交到github,链接在后面给出
打开本地网页访问:localhost:18000
服务端环境为linux环境,系统为CentOS-8,Node.js版本为v8.11.3,Linux环境和windows环境部署的时候有点区别,特别是安装puppeteer时需要注意安装puppeteer时会报以下错误
ERROR:FailedtodownloadChromiumr722234!Set"PUPPETEER_SKIP_CHROMIUM_DOWNLOAD"envvariabletoskipdownload.Error:EACCES:permissiondenied,mkdir'/opt/video-url-analysis/node_modules/puppeteer/.local-chromium'
因为安装puppeteer时会安装Chromium,需要权限,因此在linux环境下使用以下命令安装
npminstallpuppeteer@2.1.1--unsafe-perm=true--allow-root安装完毕后启动程序,成功运行并抓取网页视频!
linux下启动浏览器headless需要设置为true,添加args参数
constbrowser=awaitpuppeteer.launch({headless:true,//是否启用无头浏览默认为trueargs:['--no-sandbox','--disable-setuid-sandbox']});其他异常错误:1.Failedtolaunchthebrowserprocess
Failedtolaunchthebrowserprocess...errorwhileloadingsharedlibraries:libXss.so.1:cannotopensharedobjectfile:Nosuchfileordirectory应该是系统缺少某些库或者组件(我这边使用命令后解决了这个问题)
sudoyum-yinstalllibXScrnSaver-1.2.2-6.1.el7.x86_64或者直接重新安装chromium,手动安装chromium后解决问题
sudoyuminstall-ychromium2.使用yum安装软件依赖出错,一直提示找不到软件包
[root@localhostvideo-url-analysis]#sudoyuminstall-ychromium上次元数据过期检查:0:00:47前,执行于2022年01月20日星期四21时35分27秒。未找到匹配的参数:chromium错误:没有任何匹配:chromium原因是CentOS8没有安装epel源的问题,安装epel源后问题解决:yuminstallepel-release
1.安装依赖
npminstall2.本地开发
npmrundev打开本地网页访问:localhost:18000
windows环境下开发比较顺利,由于本人是前端切图仔,服务器接触较少,所以linux服务端部署遇到的问题较多,因此记录一下解决问题的过程,方便后续开发者遇到问题能够顺利解决。服务端知识有所欠缺,如有不足,还请海涵!