V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gdtv
V2EX  ›  PHP

请问 PHP 采集 Discuz!论坛的帖子,可是论坛开启了 javascript 的防采集功能,怎么办?

  •  
  •   gdtv · 2017-03-10 16:39:53 +08:00 · 2277 次点击
    这是一个创建于 2816 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题有点长,希望大家有耐心看。

    采集帖子页面的时候,对方服务器会随机返回类似如下的 javascript 代码,这个代码的功能是给当前 url 加上_dsign 参数然后跳转。

    <script type="text/javascript">_x0cyY = 'href';function yG(yG_){function _y(yG_){function i(){return getName();}function yG_(){}return i();return yG_}; return _y(yG_);}function getName(){var caller=getName.caller;if(caller.name){return caller.name} var str=caller.toString().replace(/[\s]*/g,"");var name=str.match(/^function([^\(]+?)\(/);if(name && name[1]){return name[1];} else {return '';}}mI='2';W0=function(){'return W0';return 'd';};O8='i';L1=function(){'return L1';return 'e';};_rZ29z = 'assign';function lV(){'lV';function _l(){return '='}; return _l();}function A59(){'A59';function _A(){return '=3'}; return _A();}va8D='n=3';bV=function(){'bV';var _b=function(){return '.'}; return _b();};c0=function(){'c0';var _c=function(){return 'd'}; return _c();};_kbOOO = 'replace';mg=function(){'mg';var _m=function(){return 'm'}; return _m();};dy='d';function uI(){'uI';function _u(){return '6'}; return _u();}_f5116 = window;PM=function(){'return PM';return 'u';};function f5bi(){'return f5bi';return 'd&t'}function G518(){'G518';function _G(){return '96&'}; return _G();}KW='w';OC='t';function iCA4(iCA4_){function sig(){return getName();};return sig();return 'iCA4'}_udLtF = location;function d6(){'return d6';return '_'}function g6(g6_){function b(){return getName();};return b();return 'g6'}k2=function(){'k2';var _k=function(){return 'h'}; return _k();};W74=function(W74_){'return W74';return W74_;};uC1a=function(){'return uC1a';return 'fb8';};_udLtF[_x0cyY]=(function(){'return pGmD';return '/fo'})()+(function(){'return Bz';return (function(){return 'r';})();})()+PM()+mg()+bV()+(function(){'return HaA5';return 'php'})()+(function(wwP_){return (function(wwP_){return wwP_;})(wwP_);})('?m')+(function(){'return Xz';return 'o'})()+dy+lV()+(function(){'return fU';return 'v'})()+O8+L1()+KW+OC+k2()+(function(){'return aV';return (function(){return 'r';})();})()+'ea'+f5bi()+yG('Mz')+c0()+A59()+mI+(function(){'return M33';return '7'})()+G518()+d6()+W0()+iCA4('qHs8')+va8D+g6('xf')+uI()+W74('e3')+uC1a();_f5116[_x0cyY]=(function(){'return pGmD';return '/fo'})()+(function(){'return Bz';return (function(){return 'r';})();})()+PM()+mg()+bV()+(function(){'return HaA5';return 'php'})()+(function(wwP_){return (function(wwP_){return wwP_;})(wwP_);})('?m')+(function(){'return Xz';return 'o'})();</script>
    

    PS :不是我没格式化,是服务器返回就是这样的。
    因为这段 js 代码很复杂,我无法用 php 来解析以便获取到帖子的新的 url 。所以只好借助 PhantomJS 。

    目前我的解决方法是,用 PhantomJS 创建一个 webserver ,这个 webserver 运行这段 js 代码并获取跳转后的新 url 返回给 php 。 webserver 代码如下:

    var page = require('webpage').create();
    var server = require('webserver').create();
    var service = server.listen('127.0.0.1:22222', function (request, response) {
        var expectedContent = request.post; //接收要解析的 js 代码
        var expectedLocation = 'http://www.test.com/';
        var t;
    
        //获取取跳转后的新地址
        page.onNavigationRequested = function(url, type, willNavigate, main) {
            if(url!=expectedLocation){
                response.statusCode = 200;
                response.headers = {
                    'Cache': 'no-cache',
                    'Content-Type': 'text/html;charset=utf-8'
                };
                response.write(url);
                response.close();
                clearTimeout(t);
            }
    
        };
    
        page.setContent(expectedContent, expectedLocation); //将接收到的 js 代码放到页面里执行
        
        //如果跳转失败,或者接收到的 js 代码没有跳转功能,等待 1 秒后强制关闭
        //问题出在这里,如果提交的 js 代码跳转不成功,这里会浪费 1 秒钟才会结束,有什么办法改善一下呢?
        t = setTimeout(function(){
            console.log('no redirect');
            response.statusCode = 200;
            response.headers = {
                'Cache': 'no-cache',
                'Content-Type': 'text/html;charset=utf-8'
            };
            response.write('');
            response.close();
        },1000);
    });
    

    如果 php 采集到的帖子是一段 js 跳转代码,就将这段代码 post 到 webserver 里,让 webserver 解析 js 然后返回跳转后的 url 。

    问题:
    如果提交的 js 代码跳转不成功,或者提交了错误的或者没有跳转功能的 js 代码, webserver 会浪费 1 秒钟才会返回响应,有什么办法改善一下呢?
    或者有没有其他更好的方法可以获取到跳转后的新地址?

    第 1 条附言  ·  2017-03-10 18:54:21 +08:00

    感谢 @chairuosen , chairuosen的方法完美解决了,贴上最终的代码:

    var server = require('webserver').create();
    var service = server.listen('127.0.0.1:2222', function (request, response) {
        response.statusCode = 200;
        response.headers = {
            'Cache': 'no-cache',
            'Content-Type': 'text/html;charset=utf-8'
        };
        
        var str = request.post;
        str = str.match(/<script[^>]*>(.*)<\/script>/); 
        if(str!=null && str[1]!=null){
            str = str[1];
            var window={}; 
            var location = window.location = {href:""}; 
            eval(str); 
            console.log(location.href);
            
            response.write(location.href);
        }else{
            response.write('');
        }
        
        response.close();
    });
    
    8 条回复    2017-03-10 18:50:22 +08:00
    chairuosen
        1
    chairuosen  
       2017-03-10 16:55:45 +08:00   ❤️ 1
    var str = `<script type="text/javascript">_x0cyY = 'href';function yG(yG_){function _y(yG_){function i(){return getName();}function yG_(){}return i();return yG_}; return _y(yG_);}function getName(){var caller=getName.caller;if(caller.name){return caller.name} var str=caller.toString().replace(/[\s]*/g,"");var name=str.match(/^function([^\(]+?)\(/);if(name && name[1]){return name[1];} else {return '';}}mI='2';W0=function(){'return W0';return 'd';};O8='i';L1=function(){'return L1';return 'e';};_rZ29z = 'assign';function lV(){'lV';function _l(){return '='}; return _l();}function A59(){'A59';function _A(){return '=3'}; return _A();}va8D='n=3';bV=function(){'bV';var _b=function(){return '.'}; return _b();};c0=function(){'c0';var _c=function(){return 'd'}; return _c();};_kbOOO = 'replace';mg=function(){'mg';var _m=function(){return 'm'}; return _m();};dy='d';function uI(){'uI';function _u(){return '6'}; return _u();}_f5116 = window;PM=function(){'return PM';return 'u';};function f5bi(){'return f5bi';return 'd&t'}function G518(){'G518';function _G(){return '96&'}; return _G();}KW='w';OC='t';function iCA4(iCA4_){function sig(){return getName();};return sig();return 'iCA4'}_udLtF = location;function d6(){'return d6';return '_'}function g6(g6_){function b(){return getName();};return b();return 'g6'}k2=function(){'k2';var _k=function(){return 'h'}; return _k();};W74=function(W74_){'return W74';return W74_;};uC1a=function(){'return uC1a';return 'fb8';};_udLtF[_x0cyY]=(function(){'return pGmD';return '/fo'})()+(function(){'return Bz';return (function(){return 'r';})();})()+PM()+mg()+bV()+(function(){'return HaA5';return 'php'})()+(function(wwP_){return (function(wwP_){return wwP_;})(wwP_);})('?m')+(function(){'return Xz';return 'o'})()+dy+lV()+(function(){'return fU';return 'v'})()+O8+L1()+KW+OC+k2()+(function(){'return aV';return (function(){return 'r';})();})()+'ea'+f5bi()+yG('Mz')+c0()+A59()+mI+(function(){'return M33';return '7'})()+G518()+d6()+W0()+iCA4('qHs8')+va8D+g6('xf')+uI()+W74('e3')+uC1a();_f5116[_x0cyY]=(function(){'return pGmD';return '/fo'})()+(function(){'return Bz';return (function(){return 'r';})();})()+PM()+mg()+bV()+(function(){'return HaA5';return 'php'})()+(function(wwP_){return (function(wwP_){return wwP_;})(wwP_);})('?m')+(function(){'return Xz';return 'o'})();</script>
    `;
    str = str.match(/<script[^>]*>(.*)<\/script>/)[1];
    var window={};
    var location = window.location = {href:""};
    eval(str);
    console.log(location.href);
    gdtv
        2
    gdtv  
    OP
       2017-03-10 17:47:56 +08:00
    @chairuosen 谢谢,不过你的代码只能获取到跳转前的 url ,不能获取到跳转后的 url 。
    chairuosen
        3
    chairuosen  
       2017-03-10 17:58:43 +08:00
    @gdtv 这段代码只能获取这个 url ,另有跳转的事,就应该是请求这个 url 之后的事了,它也许 301 到别处了
    chairuosen
        4
    chairuosen  
       2017-03-10 18:00:39 +08:00
    @chairuosen 如果是 301 条的你就 curl -I this_url | grep Location
    lecher
        5
    lecher  
       2017-03-10 18:04:19 +08:00 via Android   ❤️ 1
    js 交给 V8 引擎去解析,拿到 js 再执行就是了。再怎么藏它都得返回给浏览器执行。

    还可以上 GitHub 搜一搜,我之前在 GitHub 上面搜到过腾讯图源解密的 js 代码。
    gdtv
        6
    gdtv  
    OP
       2017-03-10 18:31:31 +08:00
    @chairuosen 这个不是 301 的,如果是 301 就好办了,可惜这个是 js 跳转
    ColinZeb
        7
    ColinZeb  
       2017-03-10 18:43:20 +08:00   ❤️ 1
    @chairuosen 一楼的代码就是获取跳转后的,你可以试试
    gdtv
        8
    gdtv  
    OP
       2017-03-10 18:50:22 +08:00
    @chairuosen 不好意思刚才看错了,你的是对的,谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2900 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 12:19 · PVG 20:19 · LAX 04:19 · JFK 07:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.