Giter Club home page Giter Club logo

wedge's Introduction

Wedge

可配置的小说下载及阅读工具

快速开始

#!/usr/bin/env node
const Wedge = require("./wedge");
const app = new Wedge("./library");
app.start()

单页应用服务器

const Wedge = require("./wedge");
const app = new Wedge("./library");
app.server()

使用教程

//引入wedge模块
const Wedge = require("./wedge");
//创建App,参数为工作路径
var App = new Wedge(workdir);
//新建书籍
App.newBook(url);
//更新书籍
App.updateBook(uuid);
//批量新建书籍
App.newBooks([url1,url2,url3,...]);
//批量更新书籍
App.updateBooks([uuid1,uuid2,uuid3,...]);
//终端提示输入界面
App.start()

配置参数[可选]

参数配置,初次运行时会在工作路径新建json格式的配置文件,可手动修改,键名对大小写不敏感 通过App.start()进入终端界面后,亦可通过 [修改配置] 进行热更新

服务器端口

//启动Web服务时监听的端口
App.config.set('server.port',80);

网络请求参数

//请求失败重连次数
App.config.set('request.reconnect',5);
//请求超时时间
App.config.set('request.timeout',5000);
//设置代理
App.config.set('request.proxy','127.0.0.1:8087');
App.config.set('request.proxy',{host:'localhost',port:'8087'});
//关闭代理请求
App.config.set('request.proxy','');
//设置代理认证
App.config.set('request.proxyAuth',{username:'###',password:'###'});
//根据正则匹配自动切换代理
App.config.set('request.proxyAutoConfig','google.com|youtube.com');
//根据pac函数自动切换代理
App.config.set('request.proxyAutoConfig',url=>url.match(/google.com|youtube.com/));

电子书参数

//生成电子书保存路径
App.config.set('ebook.directory','../ebook');
//电子书格式,默认epub
App.config.set('ebook.formation','epub');
/*
是否创建电子书,子进程命令
-1——发生修改后自动创建新的电子书(包括书籍metadata变动或有下载新章节)
1——每次调用生成命令都会创建新的电子书
0——关闭该功能
*/
App.config.set('ebook.activated',-1);
//章节过滤器,程序会自动编译成函数
/*语法
关键词:title,content,id,index,date,title.length,content.length
逻辑运算:~(非),&(且),|(或)
字符匹配:/pattem/
数值范围:<x,y>(大于等于x且小于等于y),<x>(等于x)
示例:
筛选标题为(第【数字】章)开头的章节 —— title:/^第\d+章/
筛选标题为(第200章)开头的章节 —— title:/第200章/
筛选内容字符长度大于等于500的章节 —— content.length:<500,>
筛选序列在100到200之间的章节 —— index:<100,200>
筛选内容【不】含有【膜法】字符的章节 —— ~content:/膜法/
筛选下载日期大于2017-01-01的章节 —— date:<1483228800000,>
组合筛选 —— (title:/^第\d+章/ & content.length:<500,>) | content.length:<2000,>
*/
App.config.set('ebook.filter','content.length:<500,>');
//电子书生成后自动打开文件目录
App.config.set('ebook.opendirectory',false);
//电子书生成后自动打开文件
App.config.set('ebook.openebookfile',false);

电子书格式

txt——这个不用介绍了,纯文本格式的,编码用的utf-8

fb2——FictionBook格式,实际上就是一个xml文件

epub——Electronic Publication格式,文件实际上是一个zip压缩文件,内部是网页文件、元数据文件和索引文件,为了兼容旧设备,默认为Version2 格式

epub3——Electronic Publication Version 3

umd——Universal Mobile Document格式,有专门的数据结构,压缩算法还是DEFLATE

docx——微软Office的docuemnt格式,文件实际上是一个zip压缩包,内部文件是xml格式,基于open document标准生成

odt——OpenDocument Tex格式,和docx类似,也是一个xml文件的压缩包

rtf——Rich Text Format格式

ebk3——掌阅iReader的专用格式,由于格式没有完全公开暂时不支持封面图片

html——单页网页文件,可用于生成pdf和mobi

htmlz——压缩的单页网页文件+带元数据文件

json——JSON格式

txt.zip——txt格式的压缩文件

fb2.zip——fb2格式的压缩文件

html.zip——分章节的html压缩文件

htmls——分章节的html文件,会在对应路径自动创建文件夹存放

txts——分章节的txt文件,会在对应路径自动创建文件夹存放

wbk——作者自定义的电子书格式,无损高压缩率,主要用于导出备份书籍,可直接通过作者提供的脚本工具转换成其他格式

pdf——Portable Document Format格式,自己实现PDF排版难度太大,推荐生成html后用浏览器打开并保存为pdf

chm——微软help文件,LZX压缩算法,非window系统下要自己实现,所以不兼容*nix系统

mobi——HUff和LZ77压缩,JS版本的压缩算法已完成,但文件格式定义尚有一些不清楚的地方,现在暂时不支持,推荐用kindlegen或者calibre转换

azw3——同上

snb——盛大bambook格式,bzip2压缩,由于Bambook基本已经退出市场,故删除该格式

线程参数

//执行章节下载时的并行数目
App.config.set('thread.execute',5);
//批量新建小说时的并行数目
//总线程=thread.execute*thread.new
App.config.set('thread.new',5);
//批量更新小说时的并行数目
App.config.set('thread.update',5);
//合并目录时的并行数目
App.config.set('thread.merge',5);
//下载图片时的并行数目
App.config.set('thread.image',5);

数据库参数

//实时同步本地
App.config.set('database.sync',true);
//添加新书时在数据库中检索书籍是否已经存在
//关闭时将在本地检索书籍是否已经存在
App.config.set('database.check',false);
//通过App.start()启动终端模式的时候,打印数据表格时允许显示的关键词
App.config.set('database.showKeys', ["uuid","title","author","classes","isend","date","source"]);

书籍参数

//根据本地章节文件同步目录
App.config.set('book.sync',true);
//自动检查目录,添加已有的章节信息或移除已被删除的章节
App.config.set('book.check',true);
//如果存在相同小说时,是否切换新的的源
App.config.set('book.changesource',false);
//切换新的的源后是否覆盖旧章节
App.config.set('book.override',false);
//章节中发现图片链接是是否下载图片到本地,可用于图片采集或者漫画下载
App.config.set('book.imagelocalization',false);
//图片链接的文件后缀过滤规则
App.config.set('book.imageExts',[".jpg",".jpeg",".png",".gif",".webp",".bmp"]);
//是否从起点腾讯等原创网站搜索书籍信息
//建议开启,当下载网站不在规则库中能够辅助搜集书籍信息
App.config.set('book.searchmeta',true);
//过滤书籍数目中链接相同的章节
App.config.set('book.unique.source',true);
//过滤书籍数目中标题相同的章节
App.config.set('book.unique.title',false);
//深度下载,如果章节内容中存在超链接,将下载该链接内容
App.config.set("book.deepdownload",true);
//设置最大下载深度
App.config.set("book.maxdepth",2);

App参数

//输出运行日志
App.config.set('app.log',true);
//输出运行日志到本地文件
App.config.set('app.log','LOG.txt');
//输出debug信息
App.config.set('app.debug',true);
//总的网络重连次数=retry * request.reconnect
//获取书籍元数据失败时的重试次数
App.config.set('app.reTry.meta',3);
//获取书籍目录失败时的重试次数
App.config.set('app.reTry.index',3);
//获取书籍封面图片失败时的重试次数
App.config.set('app.reTry.cover',3);
//获取书籍章节内容失败时的重试次数
App.config.set('app.reTry.chapter',3);
//获取章节内图片失败时的重试次数
App.config.set('app.reTry.image',3);

###其他配置 ####小说搜索引擎配置 config/searcher.json 以[若出中文网]为例

  {//%title%会被替换成书名
    "url": "http://a.ruochu.com/jsonp/search/",//请求地址
    "query": "queryString=%title%&objectType=2&page=1&pageSize=25",
    "method": "GET",//默认请求方式为GET,可省略
    "dataType": "json",//返回数据为json格式
    "charset": "gbk",//charset默认为utf-8,请求参数非合法的url字符会编码成对应字符
    "name": ".ruochu.com",
    "headers":{//某些网站需要配置header请求头,否则请求失败,不设置headers的时候,程序会自动以XHR的请求头发送
      "referer": "http://www.ruochu.com/search/?queryString=%title%"
    },
    "parse": "json.voRF.items.map(o=>['http://www.ruochu.com'+o.object.url,o.object.name])"//json的解析函数
  }

以[晋江文学]为例

  {//晋江文学自己的搜索引擎垃圾,只能通过第三方搜索引擎进行搜索
    "url": "https://www.baidu.com/s",
    "query": "ie=utf-8&rn=50&wd=%title%&si=www.jjwxc.net&ct=2097152",//设置baidu站内搜索
    "selector": ".result h3.t a",//返回为html格式,可以通过Selector筛选链接,默认选择器为':header a,img a'
    "engine": "baidu",
    "replace": [{".*《(.*)》.*":"$1"}],//链接的text需要进行替换
    "filter": "http://www.jjwxc.net/onebook.php\\?novelid=\\d+",//过滤符合要求的链接
    "name": "www.jjwxc.net"
  }

全局替换器

config/Filter.json

{
    "chapterTitle":[
        "[\\(\\[(].*?[0-9一二三四五六七八九十]更.*?[\\)\\])]",
        "[\\(\\[(].*?(月票|推荐|收藏).*?[\\)\\])]",
        "www.*(com|net|org|cn|in)"
    ],//全局章节标题过滤规则
    "chapterBeforeFilter":[],//内置过滤前的原始html文件的过滤规则
    "chapterAfterFilter":[
        "readx();",
        "天才(壹|一)秒记住.*为您提供精彩小说阅读。",
        "^<<",
        "手机用户请浏览.*",
        "公告:本站推荐一款免费小说APP.*",
        "[\\((]未完待续[\\s\\S]*"
    ]//内置过滤后进一步的过滤
}

线程控制器

部分站点并发请求的时候为被识别为爬虫,导致IP锁定无法访问 可在通过 App.config.set('thread.execute',1) 来限制全局的线程数 亦可以通过如下的配置线程数来限制特定站点的请求频率 config/threadLimit.json

{
  "www.qushuba.com": 1,
  "www.qu.la": 1,
  "www.paoshuba.cc": 1
}

元数据搜索排除规则

当 book.searchmeta 配置为true的时候,每次新增小说的时候都会自动搜索元数据 这一功能会获取正版来源的书籍数据,但是需要耗费一定的时间 部分网站,如本身就是正版网站,不需要启用该功能的时候 可以通过配置该规则来略过搜索来节约下载时间 config/outclude.json

[
  ".qidian.com",".qq.com", ".sogou.com",".zongheng.com",".17k.com",".jjwxc.net",".ireader.com",
  "ireader.com.cn",".readnovel.com",".motie.com",".hongshu.com",".faloo.com",".ihuaben.com",
  ".kanshu.com",".xs8.cn",".xxsy.net",".hongxiu.com",".zhulang.com",".yousuu.com",".jingyu.com",
  ".tiexue.net",".heiyan.com",".ruochu.com",".km.com","3gsc.com.cn",".tadu.com",".kujiang.com",
  ".163.com",".xiang5.com",".shuhai.com",".cjzww.com",".douban.com",".fmx.cn",".ycread.com",
  ".ycsd.cn",".longyuedu.com",".hengyan.com",".ciweimao.com",".8kana.com",".msxf.cn",".sfacg.com",
  ".youdubook.com",".ebtang.com",".itangyuan.com"
]

plugins小插件

//启用或添加插件
//修改工作路径的setting.json文件后重启程序
{
  "name": "deepQuest",
  "activated": false,//未启动
  "func": "./plugins/deepQuest"//插件脚本路径
}
//将书籍文件发送到手机阅读器;参数不齐全时自动进入终端界面提示输入
//QQ阅读器(默认开启)
App.sendToQQ(ip,[files]);
App.sendToQQ();
//iReader阅读器(默认开启)
App.sendToiReader();
//搜索引擎(默认开启)
App.Engine.search(title,callback);
//设置搜索引擎;默认为sogou
App.Engine.setEngine("360");
App.Engine.setEngine("baidu");
//简单的控制台输入界面(默认开启)
App.start()
/*
  0) 返回
  1) 新建书籍
  2) 更新书籍
  3) 重新下载书籍
  4) 刷新书籍信息
  5) 生成电子书
  6) 导入书籍
  7) 导出书籍
  8) 删除书籍
  9) 删除书籍记录
  10) 导入书籍记录
  11) 修改书籍信息
  12) 批量操作
      0) 返回上一级菜单
      1) 新建书籍
      2) 更新书籍
      3) 重新下载书籍
      4) 刷新书籍信息
      5) 导出书籍
      6) 生成电子书
      7) 转换电子书
      8) 删除书籍
      9) 删除书籍记录
      10) 导入书籍记录
      11) 退出
  13) 数据库检索
      0) 返回上一级菜单
      1) 关键字检索
      2) query查询
      3) SQL查询
      4) 退出
          0) 返回上一级菜单
          1) 返回主菜单
          2) 显示表格
          3) 显示详情
          4) 过滤数据
          5) 导出数据
          6) 批量操作
              0) 返回上一级菜单
              1) 返回主菜单
              2) 更新书籍
              3) 刷新书籍信息
              4) 重新下载书籍
              5) 导出书籍
              6) 生成电子书
              7) 删除书籍
              8) 删除书籍记录
              9) 退出
          7) 退出
  14) 电子书格式转换
  15) 发送到手机[需在同一局域网下]
  16) 使用引擎搜索
  17) 修改配置
  18) 测试规则
  19) 退出
*/

添加网站规则

临时添加

App.Sites.inject(rule);

永久添加

在Wedge/lib/Sites路径下 defaut为原创小说网站, plugins为盗链网站 ![host]命名的为匹配多个网站的规则

规则文件由三部分组成:index.js, selector.js(json), replacer.js(json)

####主文件(index.js)

module.exports = {
    "host":"www.23zw.com",//站点host
    "match":[//其他相同规则的站点host,或者域名发生变动
        "www.23zw.com",
        "www.23zw.me"
    ],
    "charset":"gbk",//网页编码,推荐填写,部分网站编码混乱的时候可以不填,程序会自动解码,
    "selector":require("./selector"),
    "replacer":require("./replacer")//不设置的时候默认为{}
}

####选择器 按照jquery函数填写规则,启动时自动编译成函数,为了安全后期会改成沙盒中运行 注入函数:

  1. $.location(url) 参数为空时返回当前页面的url,参数不为空是返回相对路径的完整url地址,等效于path.resolve()函数
  2. $.getCookie(name) 返回当前页面对应name的cookie值
  3. $.decode(str,charset) 字符串解码,允许的编码:unicode(\u4eba->人) base64(5Lq65Lq6->人) html(&#4eba->人)
  4. $.encode(str,charset) 字符串编码,允许的编码:unicode base64 html
{
  "infoPage": {
    "match": "!!$('.btnlinks > a.read').length",//是否匹配书籍信息页面
    "indexPage": "$.location($('.btnlinks > a.read').attr('href'))",//书籍目录页的链接
    "footer": "$('.footer').length",//页面footer,防止网络延迟下的页面内容缺失,可直接填true
    "bookInfos": {//采集书籍信息
      "title": "$('#content h1').text()",//书籍名称
      "author": "$('th:contains(作者)').next('td').text()",//书籍作者
      "classes": "$('th:contains(类别)').next('td').text()",//书籍分类
      "isend": "$('th:contains(状态)').next('td').text()",//书籍完结状态
      "cover": "$.location($('a.hst img').attr('src'))",//书籍封面链接
      "brief": " $('p:contains(内容简介)').nextAll('p').html()"//书籍简介
    }
  },
  "indexPage": {
    "match": "!!$('.tags').length",//是否匹配书籍目录页
    "infoPage": "$.location($('.bdsub > dl > dt > a').last().attr('href'))",//书籍信息页的链接
    "footer": "!!$('.tags').length",
    "filter": "$('td:contains(更新重要通告)').remove()",//过滤信息
    "bookIndexs": "$('td.L a').map((i,v)=>({href:$.location($(v).attr('href')),text:$(v).text()})).toArray()"//书籍章节链接,返回{href:,text:}格式的数组
  },
  "contentPage": {
    "match": "!!$('#footlink').length",//是否匹配章节页
    "footer": "!!$('#footlink').length",
    "chapterInfos": {
      "source": "$.location()",//页面地址
      "title": "$('h3').text()",
      "content": "$('#contents').html()"//页面内容
    }
  }
}

如果需要模拟ajax请求,以QQ读书为例,构造一个请求对象

{
  "contentPage": {
    "match": "/^http:\\/\\/chuangshi\\.qq\\.com\\/\\w+\\/\\w+\\/\\w+\\-r\\-\\d+\\.html/i.test($.location())",
    "footer": "true",
    "request":{
      "url" : "$.location().replace('http://dushu.qq.com/read.html?bid=','http://dushu.qq.com/read/').replace('&cid=','/')",
      "method" : "'POST'",
      "data" : "'lang=&w=830&fontsize=14'",
      "dataType" : "'json'",
      "success" : "data=>{$('.readPageWrap').html(data.Content);$('div.bookreadercontent').find('p').last().remove();return $('div.bookreadercontent').html();}"
    }
  }
}

如果页面是分页的,需要连续采集多个页面合成一页,如论坛或者漫画

{
 "contentPage": {
    "match": "!!$('#footlink').length",//是否匹配章节页
    "footer": "!!$('#footlink').length",
    "chapterInfos": {
      "source": "$.location()",//页面地址
      "content": "$('#contents').html()"//页面内容
      "nextPage": "$.location($('a.next').attr('href'))"//下一页链接,分页显示时使用,如漫画
    }
  }
}

替换器

结构同上,可省略 字符串会编译成正则表达式进行替换 {key:value}对象格式会将key编译成正则表达式并替换成value

{
  "infoPage": {
    "bookInfos": {
      "title": ["全文阅读"]
    }
  },
  "contentPage": {
    "chapterInfos": {
      "content": ["看最快更新","一秒记住.*?免费阅读!"]
    }
  }
}

wedge's People

Contributors

lz0211 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

wedge's Issues

tadu的要更新一下了

刚刚试了下,抓不到章节,然后去查了下,应该要改成这样的了:

"content": "$('#partContent').html()"

default里的www.tadu.com

EBK 转TXT

有偿求助EBK格式文件转TXT格式算法。

起点的一旦章节数目过多好像会失效

刚刚试了一下,其中有一个一千多章失效了,其他的有一两千章的也失效了……
限免里的:神道丹尊随身带着女神皇抬棺匠
都是这种情况

testRule输出:

{ title: '神道丹尊',
  author: '孤单地飞',
  classes: '东方玄幻',
  uuid: 'b2ca589a-c4da-04ee-193c-06dc368bd5da',
  source: 'http://book.qidian.com/info/3607314',
  origin: 'http://book.qidian.com/info/3607314',
  isend: false,
  date: 1492745610721,
  brief: '绝世强者、一代丹帝凌寒为追求成神之路而殒落,万年后携《不灭天经》重生于
同名少年,从此风云涌动,与当世无数天才争锋,重启传奇之路,万古诸天我最强!\n普通
群:273857096。VIP群(只限付费读者):539195580',
  cover: 'http://qidian.qpic.cn/qdbimg/349573/3607314/180' }
[]

下载章节的请求最后变负数了……

小说来自:

http://www.23us.com/

其中一段log记录:

[getChapters]:-1269052 quests is running, 0 quests is waiting...
[getChapters]:-1269052 quests is running, 0 quests is waiting...
[getChapters]:-1269052 quests is running, 0 quests is waiting...
[getChapters]:-1269052 quests is running, 0 quests is waiting...
[getChapters]:-1271291 quests is running, 0 quests is waiting...
[getChapters]:-1271291 quests is running, 0 quests is waiting...
[getChapters]:-1271291 quests is running, 0 quests is waiting...
[getChapters]:-1271291 quests is running, 0 quests is waiting...

起点的偶尔会有章节内容抓取过多的现象

稍微看了看,抓多的几乎都是作者开的非正文单章(一般都是求月票或者请假什么的)。
json示例:

{
  "title": "开单章拉月票!!!",
  "id": "00149",
  "source": "http://vipreader.qidian.com/chapter/1255901/24891099",
  "date": 1492925305318,
  "content": "<img src=\"//qidian.qpic.cn/qdbimg/349573/1255901/300\" width=\"300\" height=\"300\">\n手机阅读\n扫描下载起点读书客户端\n<img src=\"00149/00000.png\">\n最近阅读\n快速导航\n分类频道\n其它\n\n\n\n\n点击书签后,可收藏每个章节的书签,“阅读进度”可以在个人中心书架里查看\n开单章拉月票!!!\n179字\n2009.09.02 10:01\n写书难,写好书更难!!每个VIP的作者拉月票的都很正常!!也都有这个资格。所以,老安就来拉月票了。\n老安素来信奉与人为善的做人原则。但不知自己哪里得罪了一些人,老是挂马甲来我书评区捣乱,对本书进行打压。\n还请各位善意或者恶意的人,对本书“笔下留情”,适当批评是可以的,但谩骂,还外带侮辱作者的智商,就有些太过了。\n老安,以后每天力求9000字保证,在此求月票!!!\n|\n|\n目录\n设置\n手机阅读\n加入书架\n返回书页\n起点游戏\n打赏\n投票\n评论"
}

请教一下章节内容规则

刚刚试着写了8站的规则,基本上需要抓的信息都抓到了,查看日志时发现章节目录列表应该是抓成功的,但只剩下章节内容没抓成功,请问一下规则哪里写错了?
测试小说:白雪的祭祀(限免的)

selector.json

{
  "infoPage": {
    "match": "/^http:\\/\\/www\\.8kana\\.com\\/book\\/\\d+\\.html$/i.test($.location())",
    "indexPage": "$.location()",
    "footer": "$('.footer').length > 0",
    "bookInfos": {
      "origin": "$.location()",
      "source": "$.location()",
      "title": "$('h2').text()",
      "author": "$('a.authorName.manColor').text()",
      "classes": "$('ul > li.navTopL_list.type_slide.navTopL_current > a').text()",
      "isend": "$('div.BookInfoCalendar_MainBtn').text()",
      "cover": "$.location($('div.left.bookContainImgBox > a > img').attr('src'))",
      "brief": "$('a > p').html()",
      "keywords": "[this.title($),this.author($),this.classes($)].concat($().map((i,x)=>$(x).text()).toArray()).join(',')"//不知道用途,复制自起点的
    }
  },
  "indexPage": {
    "match": "/^http:\\/\\/www\\.8kana\\.com\\/book\\/\\d+\\.html$/i.test($.location())",
    "infoPage": "$.location()",
    "footer": "$('.footer').length > 0",
    "filter": "$('#btnChapterMore').remove()",
    "bookIndexs": "$('#chapter_con').find('a').map((i,v)=>({href:$.location($(v).attr('href')),text:$(v).text().trim()})).toArray()"
  },
  "contentPage": {
    "match": "/^http:\\/\\/www\\.8kana\\.com\\/read\\/\\d+\\.html$/i.test($.location())",
    "footer": "$('.footer').length > 0",
    "filter": "$('.myContent').find('span').remove()",
    "chapterInfos": {
      "title": "$('h2').text()",
      "source": "$.location()",
      "content": "$('.myContent').html()"
    }
  }
}

部分日志记录:

getBookMeta
createBook
checkBookCover
getBookIndexs
[getBookIndexs]:1 quests is running, 0 quests is waiting...
[getBookIndexs]:0 quests is running, 0 quests is waiting...
getChapters
[getChapters]:1 quests is running, 41 quests is waiting...
getChapter
………………………………
[getChapters]:16 quests is running, 0 quests is waiting...
getChapter
[getChapters]:15 quests is running, 0 quests is waiting...
getChapterContent
[getChapters]:14 quests is running, 0 quests is waiting...
[getChapters]:13 quests is running, 0 quests is waiting...
[getChapters]:12 quests is running, 0 quests is waiting...
[getChapters]:11 quests is running, 0 quests is waiting...
[getChapters]:10 quests is running, 0 quests is waiting...
[getChapters]:9 quests is running, 0 quests is waiting...
[getChapters]:8 quests is running, 0 quests is waiting...
[getChapters]:7 quests is running, 0 quests is waiting...
[getChapters]:6 quests is running, 0 quests is waiting...
[getChapters]:5 quests is running, 0 quests is waiting...
[getChapters]:4 quests is running, 0 quests is waiting...
[getChapters]:3 quests is running, 0 quests is waiting...
[getChapters]:2 quests is running, 0 quests is waiting...
[getChapters]:1 quests is running, 0 quests is waiting...
[getChapters]:0 quests is running, 0 quests is waiting...
end...

提交规则

plugins网址:http://www.23us.com/

index.js

module.exports = {
    "host":"www.23us.com",
    "match":[
        "www.23us.com"
    ],
    "charset":"gbk",
    "selector":require("./selector"),
    "replacer":require("./replacer")
}

replacer.json

{
  "infoPage": {
    "match": null,
    "indexPage": null,
    "footer": null,
    "bookInfos": {
      "source": null,
      "title": null,
      "author": null,
      "classes": null,
      "isend": null,
      "cover": null,
      "brief": null,
      "keywords": null
    }
  },
  "indexPage": {
    "match": null,
    "infoPage": null,
    "footer": null,
    "bookIndexs": null
  },
  "contentPage": {
    "match": null,
    "footer": null,
    "chapterInfos": {
      "title": null,
      "source": null,
      "content": "[(.]*未完待续.*[)]"
    }
  }
}

selector.json

{
  "infoPage": {
    "match": "/\\/book\\/\\d+/i.test($.location())",
    "indexPage": "$.location($('.btnlinks > a.read').attr('href'))",
    "footer": "$('.footer').length > 0",
    "bookInfos": {
      "source": "$.location()",
      "title": "$('h1').text().replace(' 全文阅读','')",
      "author": "$('th:contains(文章作者)').next('td').text()",
      "classes": "$('th:contains(文章类别)').next('td').text()",
      "isend": "$('th:contains(文章状态)').next('td').text()",
      "cover": "$.location($('a.hst img').attr('src'))",
      "brief": " $('#sidename').prev('p').html()"
    }
  },
  "indexPage": {
    "match": "/\\/html\\/\\d+\\/\\d+/i.test($.location())",
    "infoPage": "$.location($('a:contains(返回书页)').attr('href'))",
    "footer": "$('#a_footer').length > 0",
    "filter": null,
    "bookIndexs": "$('td.L a').map((i,v)=>({href:$.location($.location()+$(v).attr('href')),text:$(v).text()})).toArray()"
  },
  "contentPage": {
    "match": "/\\/html\\/\\d+\\/\\d+\\/\\d+\\.html$/i.test($.location())",
    "footer": "$('#a_footer').length > 0",
    "chapterInfos": {
      "title": "$('dd > h1').text()",
      "source": "$.location()",
      "content": "$('#contents').html()"
    }
  }
}

提一个bug?

在这个网站上http://www.23us.com/抓取时,由于网站偶尔会出问题导致无法连接,但在log文件中一样会有相关记录,然而实际保存文件却不是连续的(eg:实际存在的文件为00001.json,00002.json,00003.json,00004.json,00005.json,00015.json,中间会缺少06-14的json文件)。

书客的规则好像失效了

刚刚试了下这本,发现爬下来的章节内容都是undefined。

{
  "title": "本书中比企谷八幡的资料",
  "id": "00000",
  "source": "http://www.hbooker.com/chapter/book_chapter_detail/100068865",
  "date": 1492498776504,
  "content": "undefined"
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.