能不能帮分析下这个网页的 js 和 css 是怎么实现的 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
chinaglwo
V2EX    Javascript

能不能帮分析下这个网页的 js 和 css 是怎么实现的

  •  
  •   chinaglwo 2015-12-14 14:50:34 +08:00 4164 次点击
    这是一个创建于 3594 天前的主题,其中的信息可能已经有所发展或是发生改变。

    http://www.99csw.com/book/3906/134399.htm

    按 f12 打开网页,可以看到<div id="content">后面是文章内容,每个段落都是一个 div ,但是都是不可见的,而且是乱序的,不是网页上所看到的文章内容。

    然后继续往下,到了<span id="note_box" style="display: none;"><span class="note"></span><span class="arrow"></span></span> ,再下面的 div 开始,有一些是真正的文章内容,规律是第一个 div 是真实内容,然后每隔 5 个 div ,也就是第 7 个 div 又是真实内容,中间的 5 个 div 也是不可见的。

    然后我滚动网页往下,会加载新的 div(新的文章内容),也是和上面的每隔 5 个 div 规律一样,同时<span id="note_box"之前的 div 在消失,也没有新的 ajax 请求产生。

    页面滚到最下方,最前面的 div 都消失了。

    22 条回复    2015-12-19 17:17:25 +08:00
    XianZaiZhuCe
        1
    XianZaiZhuCe  
       2015-12-14 16:01:46 +08:00
    我都不知道怎么说,就这么实现的啊,可能他是为了 SEO ?
    你想用 js 怎么控制就怎么控制吧
    XianZaiZhuCe
        2
    XianZaiZhuCe  
       2015-12-14 16:05:50 +08:00
    另外可能也是防止被爬?
    imt
        3
    imt  
       2015-12-14 16:27:07 +08:00   1
    cOntent= {
    index: 0,
    step: 5,
    star: 0,
    add: 0,
    state: 'load',
    showState: 'no',
    childNode: [],
    load: function () {
    var e = base64.decode(document.getElementsByTagName('meta')[4].getAttribute('content')).split(/[A-Z]+%/);
    var j = 0;

    function r(a) {
    var c = '';
    var d = document.createElement('span');
    for (var i = 0; i < 20; i++) {
    var n = Math.floor(Math.random() * 99001 + 1000);
    c += String.fromCharCode(n)
    };
    var b = ['。', ':', '?', '!', '', '…', ';', ',', '”', ''];
    c += b[Math.floor(Math.random() * b.length)];
    d.style.color = '#fff';
    d.style.fOntSize= '0';
    d.style.lineHeight = '0';
    d.style.position = 'absolute';
    d.style.top = 0;
    d.style.left = 0;
    d.appendChild(document.createTextNode(c));
    a.appendChild(d);
    return a
    };
    for (var i = 0; i < e.length; i++) {
    if (e[i] < 5) {
    this.childNode[e[i]] = r(this.box.childNodes[i + this.star]);
    j++
    } else {
    this.childNode[e[i] - j] = r(this.box.childNodes[i + this.star])
    }
    };
    this.show()
    },
    check: function () {
    return this.showState == 'yes' && content.button.style.display != 'none' && this.offsetTop + this.button.offsetTop - Math.max(document.body.scrollTop, document.documentElement.scrollTop) < document.documentElement.clientHeight ? true : false
    },
    init: function (a, b) {
    if (!b) {
    reurn false
    };
    this.time = new Date().getTime();
    this.box = a;
    this.button = b;
    this.offsetTop = 0;
    this.randomCOntent= [];
    this.hiddenItem = [];
    this.showItem = [];

    function random() {
    return String.fromCharCode(Math.floor(Math.random() * 25 + 97)) + Math.floor(Math.random() * (1000000000))
    };
    var c = document.styleSheets[2];
    for (var i = 0; i < 100; i++) {
    this.showItem.push(random());
    this.hiddenItem.push(random())
    }
    if (c.insertRule) {
    c.insertRule('#content .' + this.hiddenItem.join(',#content .') + '{display:none;}', 0);
    c.insertRule('#content .' + this.showItem.join(',#content .') + '{display:block;}', 0)
    } else {
    for (var i = 0; i < this.hiddenItem.length; i++) {
    c.addRule('#content .' + this.hiddenItem[i], 'display:none');
    c.addRule('#content .' + this.showItem[i], 'display:block')
    }
    };
    for (var i = 0; i < this.box.childNodes.length; i++) {
    if (this.box.childNodes[i].tagName == 'H2') {
    this.star = i + 1
    }
    if (this.box.childNodes[i].tagName == 'DIV' && this.box.childNodes[i].className != 'chapter') {
    break
    }
    };
    /\/([0-9]+)\/([0-9]+)\./.test(location.href);
    this.sid = RegExp.$2;
    this.load();
    window.Onscroll= function () {
    if (content.check()) {
    content.showNext()
    }
    }
    },
    show: function () {
    this.showState = 'no';
    var a = 0;
    for (var i = this.index; i < this.childNode.length; i++) {
    if (this.childNode[i].nodeType != 1) {
    continue
    };
    a += this.childNode[i].innerHTML.length;
    this.index = i + 1;
    this.childNode[i].className = content.showItem[Math.floor(Math.random() * 100)];
    this.box.appendChild(this.childNode[i]);
    for (var j = 0; j < 5; j++) {
    var b = this.childNode[Math.floor(Math.random() * this.childNode.length)].cloneNode(true);
    b.className = content.hiddenItem[Math.floor(Math.random() * 100)];
    this.box.appendChild(b)
    };
    if (a > 500) {
    break
    }
    }
    var c = getCookie(this.sid);
    if (!c || c < this.index || c > this.childNode.length + 1) {
    addCookie(this.sid, this.index, location.pathname)
    }
    content.time = getCookie(this.sid) > this.index ? 0 : new Date().getTime();
    if (this.index >= this.childNode.length) {
    this.button.style.display = 'none'
    } else {
    this.showState = 'yes';
    if (this.check()) {
    this.showNext()
    }
    }
    },
    showNext: function () {
    if (this.showState == 'no') {
    return false
    };
    this.showState = 'no';
    setTimeout(function () {
    content.show()
    }, Math.max(0 - (new Date().getTime() - content.time), 0))
    }
    };


    只能帮你到这里了
    qiayue
        4
    qiayue  
    PRO
       2015-12-14 16:52:51 +08:00   1
    对方做了防采集,你如果按照 html 中的顺序,文章段落四乱的。
    他这是加载后用 js 调整了顺序,你只需要按照他的 js 去还原就可以
    KunsLand
        5
    KunsLand  
       2015-12-14 21:40:23 +08:00   1
    推荐一个网站, http://jsbeautifier.org/
    楼主可以试试把那些看不懂的 js 文件内容复制到里面,会有神奇的结果等着你。
    chinaglwo
        6
    chinaglwo  
    OP
       2015-12-14 22:37:30 +08:00
    @imt 感谢了,我学习一下
    chinaglwo
        7
    chinaglwo  
    OP
       2015-12-14 22:38:52 +08:00
    @qiayue 我是想学学怎么采集,学习 js
    KunsLand
        8
    KunsLand  
       2015-12-14 22:40:07 +08:00   1
    有点意思,我就深入进去了,最后找到了恢复段落顺序的办法,下面列出关键步骤:
    1. Chrome 查看源码,地址栏输入: view-source:http://www.99csw.com/book/3906/134399.htm
    2. 从网页源码中找到__第 5 个 meta 标签__,具体内容为:
    ```html
    <meta name="client" cOntent="MTdFJTM3UyUzM0klNDJSJTI5TiU2SCUyN08lNDFBJTM5VSUxNUElMjJEJTMxVCUyNU8lNDBVJTEyTSUxNkwlNVUlNDNMJTdZJTBDJTI3WSUxNUglMjJTJTE0VCUyNUwlNDVHJTM3SiUyMFklMTlFJTMxVSU5USUzNkklMjFJJTExWSUzQSU0WiUzMUklNDFYJTI2ViUyVCUxUCUzOUUlMzdUJTE0UiUxNg==" />
    ```
    这个 meta 标签的 content 值是经过 base64.encode 处理过的段落顺序。
    3. 下载包含恢复顺序逻辑的 js 脚本文件(文件名为 99csw.js ): http://www.99csw.com/command/99csw.js
    4. 将 99csw.js 的内容复制到 http://jsbeautifier.org/
    5. 在 jsbeautifier 处理后的内容中找到 @imt 列出的 content 的内容,以及 content 前面的 base64 对象部分的内容。
    6. 只需看 content 对象的 load 函数的第一句话: var e = base64.decode(document.getElementsByTagName('meta')[4].getAttribute('content')).split(/[A-Z]+%/);
    这就是恢复段落顺序最关键的一步。
    7. 在 Chrome 浏览器中打开网页: http://www.99csw.com/book/3906/134399.htm
    8. 按 F12 ,打开开发者工具,点击“控制台”或“ Console ”,输入: base64.decode(document.getElementsByTagName('meta')[4].getAttribute('content')).split(/[A-Z]+%/)
    你将会看到段落顺序数组。
    chinaglwo
        9
    chinaglwo  
    OP
       2015-12-14 23:00:45 +08:00
    @KunsLand 感谢。
    我看不懂网站原有的 js ,所以之前 @imt 发的我没明白意思,看到 @KunsLand 说的网站,我才知道原来可以这么看。再经过你的解释,就明白了。接下来我继续研究下怎么弄,谢谢。
    Lullaby
        10
    Lullaby  
       2015-12-14 23:40:46 +08:00
    chinaglwo
        11
    chinaglwo  
    OP
       2015-12-14 23:49:15 +08:00
    @KunsLand
    ["17", "37", "33", "42", "29", "6", "27", "41", "39", "15", "22", "31", "25", "40", "12", "16", "5", "43", "7", "0", "27", "15", "22", "14", "25", "45", "37", "20", "19", "31", "9", "36", "21", "11", "3", "4", "31", "41", "26", "2", "1", "39", "37", "14", "16"]

    这里面有些数字没有,而有些数字重复的,怎么弄呢
    KunsLand
        12
    KunsLand  
       2015-12-15 11:45:29 +08:00   1
    数字缺失或重复,这个的看源码,你看看 content 这个对象的 load 方法的最后一个 for 循环:
    for (var i = 0; i < e.length; i++) {
    if (e[i] < 5) {
    this.childNode[e[i]] = r(this.box.childNodes[i + this.star]);
    j++
    } else { this.childNode[e[i] - j] = r(this.box.childNodes[i + this.star])
    }
    };
    简化一下就是(感觉上是某个 hash 算法的逆过程):
    for (var i = 0; i < e.length; i++) {
    if (e[i] < 5) {
    //序号不变,就是 e[i];
    j++;//j 的初值为 0 ;
    } else {
    //序号为 e[i]-j
    }
    };

    所以最终的顺序可以这么求(以下代码均可在 console 里执行,当然得打开网址: http://www.99csw.com/book/3906/134399.htm ):

    var e = base64.decode(document.getElementsByTagName('meta')[4].getAttribute('content')).split(/[A-Z]+%/);

    var c=[], a=e.map(Number);

    for(i=0;i<a.length;i++){if(a[i]<5){c.push(a[i]);j++;}else{c.push(a[i]-j);}}

    最后结果是:
    [17, 37, 33, 42, 29, 6, 27, 41, 39, 15, 22, 31, 25, 40, 12, 16, 5, 43, 7, 0, 26, 14, 21, 13, 24, 44, 36, 19, 18, 30, 8, 35, 20, 10, 3, 4, 28, 38, 23, 2, 1, 34, 32, 9, 11]
    排一下续:
    c.sort(function(a,b){return a-b;})
    结果为:
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44]
    imt
        13
    imt  
       2015-12-15 13:42:17 +08:00   1
    那么多人提到我反解的 js,那么我在贡献一条新的思路,用油猴脚本:

    [code]
    // ==UserScript==
    // @name 99csw
    // @namespace http://tampermonkey.net/
    // @version 0.9
    // @description 99csw get word
    // @author imt
    // @match http://www.99csw.com/book/*/*.htm
    // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js
    // @grant none
    // ==/UserScript==
    /* jshint -W097 */
    'use strict';

    var times=30;
    function cus_scroll(){
    if($(document).scrollTop()+document.documentElement.clientHeight>=$(document).height() && times>0){
    $("#content div[class]:visible").each(function(){
    $(this).children().remove();
    console.log($(this).html());
    });
    }else{
    $("body").animate({ scrollTop:$(document).height() }, 1000,cus_scroll);
    }
    }

    $(function(){
    $("body").animate({ scrollTop:$(document).height() }, 1000,cus_scroll);
    });
    [/code]
    chinaglwo
        14
    chinaglwo  
    OP
       2015-12-15 17:06:26 +08:00 via Android
    @KunsLand 非常感谢,每步都解释很清楚,对我帮助很大
    chinaglwo
        15
    chinaglwo  
    OP
       2015-12-15 17:07:03 +08:00 via Android
    @imt 好高深,我看不懂,但是我也非常感谢
    imt
        16
    imt  
       2015-12-16 09:23:04 +08:00   1
    @chinaglwo 就是油猴脚本,搜索一下,chrome 下直接输出原文内容哈
    chinaglwo
        17
    chinaglwo  
    OP
       2015-12-17 23:55:23 +08:00
    @imt 哇塞,试过了,自动滚动页面到最后,然后在 console 输出文章内容,超级强大了。我要好好花时间学习才行。感谢。
    imt
        18
    imt  
       2015-12-18 10:25:41 +08:00
    @chinaglwo 哈哈哈...好好学习,天天想上...
    chinaglwo
        19
    chinaglwo  
    OP
       2015-12-18 11:22:06 +08:00
    @imt 嗯嗯。我是想用火车采集,然后写个 php 插件来处理要抓取的内容,怎么调用 js ,还没搞明白。
    imt
        20
    imt  
       2015-12-18 17:42:52 +08:00
    @chinaglwo 这个是客户端采集,和服务端 php 插件不一样的.
    以你的问题为例:
    客户端采集,采集浏览器已经"渲染"排序的文章(最终文章的正确顺序),不用考虑它怎么"算法"排序的.
    而服务端彩信就是之前提到的那些"算法"找出对应的顺序,用你的 php 插件还原它的正确顺序.
    chinaglwo
        21
    chinaglwo  
    OP
       2015-12-19 11:56:54 +08:00
    @imt 嗯,火车采集器没法做渲染的动作呢
    chinaglwo
        22
    chinaglwo  
    OP
       2015-12-19 17:17:25 +08:00
    @imt 我已经用 php 还原正确顺序,搞定了,多谢。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5393 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by slitude
    VERSION: 3.9.8.5 25ms UTC 06:55 PVG 14:55 LAX 23:55 JFK 02:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86