专栏名称: 吴师兄学算法
和程序员小吴一起从初学者的角度学习算法,以动画的形式呈现解题的思路。每周四篇原创文章,期待你的鉴赏!
目录
相关文章推荐
海峡导报  ·  雷军升任中国新首富?最新回应 ·  23 小时前  
海峡导报  ·  雷军升任中国新首富?最新回应 ·  23 小时前  
嘶吼专业版  ·  网络钓鱼攻击使用隐形Unicode ... ·  2 天前  
M姐 数据合规评论  ·  实习机会 | 环球数字经济与网络数据安全团队 ·  3 天前  
M姐 数据合规评论  ·  实习机会 | 环球数字经济与网络数据安全团队 ·  3 天前  
51好读  ›  专栏  ›  吴师兄学算法

我写了个 Chrome 插件,一键下载 Pornhub 视频!

吴师兄学算法  · 公众号  · 互联网安全 科技自媒体  · 2019-12-01 19:00

主要观点总结

本文主要描述了一个读者通过编写Chrome插件来下载Pornhub网站上的视频的过程。文章介绍了插件开发过程中遇到的技术问题,如P站前端代码的变化、JS混淆技术、插件开发的关键问题等,并提供了核心的插件代码。

关键观点总结

关键观点1: P站前端代码的变化和JS混淆技术

文章介绍了读者在面对P站前端代码变化和JS混淆技术时面临的挑战,包括在寻找视频接口信息过程中遇到的问题以及解决策略。

关键观点2: 插件开发过程的关键问题

文章详细描述了插件开发过程中的关键问题,包括如何提取包含所有视频接口信息的变量,以及使用eval函数执行混淆的JS代码等。

关键观点3: 插件的核心代码

文章提供了插件的核心代码,包括content-script.js和popup.js的示例代码,并解释了这些代码的作用和实现方式。

关键观点4: 插件的使用方式和获取途径

文章介绍了插件的使用方式,包括安装插件、打开P站视频网页、通过菜单栏点击插件进行视频下载等。同时提供了插件的获取途径,包括从谷歌商店获取和通过回复关键词获取。


正文


点击蓝色“ 五分钟学算法 ”关注我哟

加个“ 星标 ”,天天中午 12:15,一起学算法

作者 | 小詹

来源 | 小詹学Python



插件获取和使用见文末,请先欣赏技术流。

小詹有个读者叫zgao,他之前写过一篇博客,爬取了 Pornhub( 下面全部简称P站) 上的视频,代码很简单,关键还好用!当时小詹就 P 站上爬取了一些考研数学视频,虽然我用不上,但是我热爱技术啊!


技术分析

之所以有今天这篇文章呢,是因为zgao (下文中的我都为读者zgao) 发现 P 站 修改了前端的代码,将视频的接口信息全部隐藏起来了,不像以前那样能直接在网页源码中找到视频链接。于是我根据最新的 P 站情况写了一个插件,能够一键下载学习视频。


以下是从分析到写插件的全过程。首先可以来对比下修改前后的 P 站:

这是以前的 P 站。


这是现在的 P 站。


这两段都是 JS 代码,但是以前的一看就很清晰明了,而现在的有一大堆的垃圾注释在里面。 不用说,肯定是做了 JS 混淆。


因为代码是被压缩过的,所以在 chrome 开发者工具里直接代码格式化。


在 network 面板中将代码格式化之后可以看的很清楚,看上面定义的那一堆变量感觉就是我们要的 url,而下面就是将变量拼接的最后的视频链接。


我在想 P 站的程序猿不会真的这么傻吧,难道就这样拼接一堆字符串??所以我就去前面找到定义的那个变量。


然后在控制台输出这个变量的值。


我整个人都傻了,P 站的程序猿这么直接的吗?那还混淆个**的代码?


以前写个 P 站的爬虫还得每个 URL 正则匹配才能提取出来。现在更省事了,都不用爬了,直接把这个变量的值取出来就什么信息都有了。


我严重怀疑P站的前端程序猿是不是写代码的时候看片去了!


所以接下来要想提取出视频的url就很容易了,直接用ExecJS这个库来执行这段被混淆过的JS代码就ok了。


但是想了想这样也太简单了吧,没什么意思。 要不我写一个Chrome的插件来完成这件事? 因为本身视频加载之前JS肯定会执行。 那么用插件的方式也更加方便。 插件开发的过程,最关键的问题就是如何将包含所有视频接口信息的变量给提取出来。


一开始我是想到是直接在浏览器的全局变量window中拿到那个变量,这是最简单的办法。我发现通过注入JS代码用console.log(window)输出的全局变量中还是没有包含flashvars_*****这个变量,不清楚为什么。我一开始认为可能是页面onload的时候还没有执行JS所以没有变量信息。后面我想了想要不执行settimeout来实现延迟执行代码,但是还是不行。

于是我决定用另外一个办法,将字符串作为代码执行。也就是写木马最常用到的eval函数。在页面加载时,通过xpath得到混淆JS代码的位置,将它作为一段字符串当成代码执行,这样同样拿到了接口信息。


给大家看一下插件最核心的两段代码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 = 0len = 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 += "

  • " + " + "" + item.key + "" + "" + " + item.val + " target='_blank'>下载" + "
  • "
        });
        boxEl.innerHTML = videoStr
    });


    popup.js的作用主要就是和content-script.js通信,相互传值。然后在插件中渲染生成页面,JS间传值主要用到了Chrome的API。 插件开发的过程中还涉及到很多细节问题,比如ico的制作,这些就不提了。


    关于插件







    请到「今天看啥」查看全文