小詹有个读者叫zgao,他以前写过一篇博客,爬取了 Pornhub(下面所有简称P站)上的视频,代码很简单,关键还好用!当时小詹就 P 站上爬取了一些考研数学视频,虽然我用不上,可是我热爱技术啊!
php
技术分析
之因此有今天这篇文章呢,是由于zgao(下文中的我都为读者zgao)发现 P 站修改了前端的代码,将视频的接口信息所有隐藏起来了,不像之前那样能直接在网页源码中找到视频连接。因而我根据最新的 P 站状况写了一个插件,可以一键下载学习视频。
如下是从分析到写插件的全过程。首先能够来对比下修改先后的 P 站:
这两段都是 JS 代码,可是之前的一看就很清晰明了,而如今的有一大堆的垃圾注释在里面。不用说,确定是作了 JS 混淆。前端
在 network 面板中将代码格式化以后能够看的很清楚,看上面定义的那一堆变量感受就是咱们要的 url,而下面就是将变量拼接的最后的视频连接。chrome
我整我的都傻了,P 站的程序猿这么直接的吗?那还混淆个**的代码?浏览器
之前写个 P 站的爬虫还得每一个 URL 正则匹配才能提取出来。如今更省事了,都不用爬了,直接把这个变量的值取出来就什么信息都有了。ide
我严重怀疑P站的前端程序猿是否是写代码的时候看片去了!函数
因此接下来要想提取出视频的url就很容易了,直接用ExecJS这个库来执行这段被混淆过的JS代码就ok了。工具
可是想了想这样也太简单了吧,没什么意思。要不我写一个Chrome的插件来完成这件事?由于自己视频加载以前JS确定会执行。那么用插件的方式也更加方便。插件开发的过程,最关键的问题就是如何将包含全部视频接口信息的变量给提取出来。学习
一开始我是想到是直接在浏览器的全局变量window中拿到那个变量,这是最简单的办法。我发现经过注入JS代码用console.log(window)输出的全局变量中仍是没有包含flashvars_*****这个变量,不清楚为何。我一开始认为多是页面onload的时候尚未执行JS因此没有变量信息。后面我想了想要不执行settimeout来实现延迟执行代码,可是仍是不行。url
因而我决定用另一个办法,将字符串做为代码执行。也就是写木马最经常使用到的eval函数。在页面加载时,经过xpath获得混淆JS代码的位置,将它做为一段字符串当成代码执行,这样一样拿到了接口信息。spa
给你们看一下插件最核心的两段代码content-script.js,也就是注入页面的JS代码。(代码可左右拖动)
function Func() {
return new Promise((resolve, reject) => {
var a = document.querySelector("#player >script:nth-child(1)").innerHTML
a = a.split('loadScriptUniqueId')[0]
var c = a.match("flashvars_[0-9]{1,}")[0]
eval(a)
var d = eval(c)
resolve(d)
})
}
window.onload = () => {
Func().then(res => {
var videoType = []
Object.keys(res).forEach((item) => {
if (item.startsWith('quality_')) {
var obj={
key:item,
val:res[item]
}
videoType.push(obj)
}
})
for(var i = 0, len = videoType.length; i < len; i++){
console.log(videoType[i].key,videoType[i].val)
}
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if(request.cmd == 'test')
sendResponse(videoType);
});
})
}
popup.js
function sendMessageToContentScript(message, callback)
{
chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
{
chrome.tabs.sendMessage(tabs[0].id, message, function(response)
{
if(callback) callback(response);
});
});
}
sendMessageToContentScript({cmd:'test', value:'test'}, function(videoType)
{
console.log(videoType);
for(var i = 0, len = videoType.length; i < len; i++){
console.log(videoType[i].key,videoType[i].val)
}
var boxEl = document.getElementsByTagName('ul')[0]
//var videoType = [{ key: 'qeqw', val: 'adasda' }, { key: 'qeqw', val: 'adasda' }, { key: 'qeqw', val: 'adasda' }]
var videoStr = ''
videoType.forEach(item => {
videoStr += "<li>" + "<label>清晰度:" + "<span>" + item.key + "</span>" + "</label>" + "<a href=" + item.val + " target='_blank'>下载</a>" + "</li>"
});
boxEl.innerHTML = videoStr
});
popup.js的做用主要就是和content-script.js通讯,相互传值。而后在插件中渲染生成页面,JS间传值主要用到了Chrome的API。插件开发的过程当中还涉及到不少细节问题,好比ico的制做,这些就不提了。
关于插件
看到这的小伙伴,其实真正吸引你的是这最后的插件吧?
插件使用方式:
-
安装插件 (下文有插件压缩包)

-
打开 P 站,打开你要下载的视频网页
-
点击菜单栏的 PH 插件便可选择清晰度进行下载( 以下图文)
Pornhub视频下载插件已经打包好(由于某些缘由,若是不能从谷歌商店安装的话,能够直接解压导入。)
回复关键词「P站插件」便可获取这款神奇的插件~