NodeJs实战——九九藏书网(一)

in with 1 comment

『九九藏书网』是一个提供出版书籍在线阅读的网站,其网站不仅拥有部分较为罕见的资源,而且校对与排版均十分不错。但是,由于其没有官方支持的客户端,并且其书籍也不支持下载阅读,所以萌生了自己做一个爬虫来获取需要的书籍的电子版,自行导入阅读器阅读的想法。

前言

严格来讲,这并不是作者第一次接触九九藏书网的资源抓取。颇久之前,我曾经写过一个 Android 平台的 App ,实现了多线程抓取该网站的图书资源并输出为 TXT 以及 EPUB 格式,同时支持打包前自行调用搜索引擎获取高清封面,以获得最理想的资源。

直到前些日子,发现该网站更新了相关的脚本,导致程序失效,而我本人因为对上个 Android 项目的不满,并不想继续更新该程序(其实只需要稍微调整下负责解密的那部分代码即可),遂直接尝试了使用接触不久的 NodeJs 来制作一个新的爬虫。

初步观察

随意打开一本书正文的网页源代码,可以发现,其内容均在 id 为 content 的 div 块中。但是,其内容却是完全乱序的。也就是说,我们通过网页看见的正文,是网页源代码经过了处理后所见到的。那接下来的思路便是,这个重新排序是如何实现的。当然,答案很简单,那便是 JavaScript 。

一般来说,通过在正文网页空白处右键,点击“检查”,即可打开开发者选项,我们就可以在此对网页进行一定程度的调试。但是事实却并不是很顺利,实际上我们看到的 JavaScript 代码是这样的。

控制台中的 Js 代码

可见,即使经过了整理,依旧无法阅读。既然直接调试行不通,那么我们迂回一下,将此网页以及有关的 js,css 资源全部拉到本地,进行调试。

其实该网页并不复杂,额外引入的必要的资源只有 99csw.css section.css 99csw.js sstyle.js section.js 这几个(ads.js 明显为广告相关,不作考虑)。 而后,进行部分删减,仅仅保证能获取到正确的文章内容即可。

精简过后的 section.js 内容如下(99csw.js 中的部分代码移入 section.js 然后不再引入 99csw.js):


function $(a) {
  return document.getElementById(a);
}

content = {
  index: 0,
  step: 5,
  star: 0,
  add: 0,
  childNode: [],
  load: function() {
    var e = base64
      .decode(document.getElementsByTagName("meta")[4].getAttribute("content"))
      .split(/[A-Z]+%/);
    var j = 0;
    for (var i = 0; i < e.length; i++) {
      if (e[i] < 3) {
        this.childNode[e[i]] = this.box.childNodes[i + this.star];
        j++;
      } else {
        this.childNode[e[i] - j] = this.box.childNodes[i + this.star];
        j = j + 2;
      }
    }
    for (var s = 0; s < this.childNode.length; s++) {
        console.log(this.childNode[s].innerText);
      }
    this.show();
  },
  init: function(a, b) {
    if (!b) {
      return 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());
    }
    if (c.insertRule) {
      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");
      }
    }
    console.log(this.box.childNodes.length);
    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;
      }
    }
    this.load();
  },
  show: function() {
    for (var i = this.index; i < this.childNode.length; i++) {
      if (this.childNode[i].nodeType != 1) {
        continue;
      }
      this.index = i + 1;
      this.childNode[i].className =
        content.showItem[Math.floor(Math.random() * 100)];
      this.box.appendChild(this.childNode[i]);
    }
    this.button.style.display = "none";
  }
};

base64 = {
  map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  decode: function(a) {
    var b = (binary = "");
    for (var i = 0; i < a.length; i++) {
      if (a.substr(i, 1) == "=") {
        break;
      }
      var c = this.map.indexOf(a.charAt(i)).toString(2);
      binary +=
        { 1: "00000", 2: "0000", 3: "000", 4: "00", 5: "0", 6: "" }[c.length] +
        c;
    }
    binary = binary.match(/[0-1]{8}/g);
    for (var i = 0; i < binary.length; i++) {
      b += String.fromCharCode(parseInt(binary[i], 2));
    }
    return b;
  }
};

content.init($("content"), $("cload"));

其余的 css 文件照常引入(网页源代码中的各种 九九藏书网 插入词靠css屏蔽。
此时,我们便获得了可以解出正确顺序的 js 代码。

Responses
  1. wendell

    不知道为啥我这里就不行, 我把所有的js和css都拉下来加载进去都不行,格式啥的倒是都不错,就是顺序一直不对

    Reply