实用前端Node.js写爬虫系列之第3章:编写小说阅读器

Posted Node全栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实用前端Node.js写爬虫系列之第3章:编写小说阅读器相关的知识,希望对你有一定的参考价值。

编写小说阅读器

之前我们通过爬取和缓存,可以获得book.json和章节信息。

{    "title": "大主宰",    "author": "作    者:天蚕土豆",    "update_time": "更新时间:2016-07-10",    "latest_chapter": "最新章节:<a href=\"4091426.html\" target=\"_blank\">第一千两百六十二章 大陆洗礼</a>",    "intro": "\n\t\t\t\t\t<p>    大千世界,位面交汇,万族林立,群雄荟萃,一位位来自下位面的天之至尊,在这无尽世界,演绎着令人向往的传奇,追求着那主宰之路。\n    无尽火域,炎帝执掌,万火焚苍穹。\n    武境之内,武祖之威,震慑乾坤。\n    西天之殿,百战之皇,战威无可敌。\n    北荒之丘,万墓之地,不死之主镇天地。\n    ......\n    少年自北灵境而出,骑九幽冥雀,闯向了那精彩绝伦的纷纭世界,主宰之路,谁主沉浮?\n    大千世界,万道争锋,吾为大主宰。\n    ..................\n</p>\n\t\t\t\t\t<p>各位书友要是觉得《大主宰》还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦!</p>\n\t\t\t\t",    "chapters": [        {            "num": "153064",            "title": "第一章已发。",            "url": "153064.html"        },        {            "num": "153065",            "title": "第一章 北灵院",            "url": "153065.html"        },        {            "num": "153066",            "title": "第二章 被踢出灵路的少年",            "url": "153066.html"        },        {            "num": "153067",            "title": "第三章 牧域",            "url": "153067.html"        },        {            "num": "153068",            "title": "第四章 大浮屠诀",            "url": "153068.html"        }    ]
}

可见,只要有了book.json就可以获得整部书的信息了。

设计

实现一个阅读器,可以有很多办法,比如整部书都完全静态化,利用模板引擎编译即可,那么有没有更简单的做法呢?

  • 假定有一个书列表页面

  • 点击某一本书,进入阅读界面

  • 在阅读界面里切换上下章

分析共性的条件

reader.html?type=0&book=330&chapter=120
  • type是分类

  • book是书的编号

  • chapter是章节的编号

很明显,这种设计是最简单的,你只需要解析querystring即可,然后按需展示。

精简结构

reader.html

<html>  <head>    <title>第十二章 出手_大主宰_笔趣阁</title>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    <link rel="stylesheet" type="text/css" href="./css/reader.css" />    <script type="text/javascript" src="./js/zepto.min.js"></script>    <script type="text/javascript" src="./js/main.js"></script> </head>  <body>  <div id="wrapper">     <div class="content_read">      <div class="box_con">       <div class="con_top">          <a href="/">小说阅读器</a> &gt;          <a href="/xiaoshuo1/">玄幻小说</a> &gt;          <a href="/0/330/">大主宰</a> &gt; 正文 <span class='chapter_title'>第十二章 出手 </span>       </div>       <div class="bookname">        <h1 class='chapter_title'>第十二章 出手</h1>          <div class="bottem1">             <a href="javascript:;" class='pre_chapter_btn'>上一章</a> ←             <a href="javascript:;" class='chapter_btn'>章节列表</a> →             <a href="javascript:;" class='post_chapter_btn'>下一章</a>             <a href="javascript:;" class='bookmark'>加入书签</a>          </div>       </div>         <div id="content">         正文加载中。。。       </div>       <div class="bottem2">         <a href="javascript:;" class='pre_chapter_btn'>上一章</a> ←         <a href="javascript:;" class='chapter_btn'>章节列表</a> →         <a href="javascript:;" class='post_chapter_btn'>下一章</a>         <a href="javascript:;" class='bookmark'>加入书签</a>       </div>    </div>   </div>  </div> </body></html>

解析QueryString

function getQueryStringByName(name){  var result = location.search.match(new RegExp("[\?\&]" + name+ "=([^\&]+)","i"));  if(result == null || result.length < 1){    return "";  }  return result[1];
}

用法

  type = getQueryStringByName('type')  book = getQueryStringByName('book')  chapter = getQueryStringByName('chapter')

很简单吧?

获取book.js

使用$.getJSON方法

  $.getJSON(type + '/' + book + '/book.json', function(data){    current_book = data;        pre_chapter_info    = current_book.chapters[parseInt(chapter) - 1]    chapter_info        = current_book.chapters[chapter]    post_chapter_info   = current_book.chapters[parseInt(chapter) + 1]        load(chapter_info)  })

加载章节

$( “#result” ).load( “ajax/test.html” );

This method is the simplest way to fetch data from the server. It is roughly equivalent to $.get(url, data, success) except that it is a method rather than global function and it has an implicit callback function. When a successful response is detected (i.e. when textStatus is “success” or “notmodified”), .load() sets the HTML contents of the matched element to the returned data. This means that most uses of the method can be quite simple

注意上面的留空

       <div id="content">         正文加载中。。。       
       </div>

代码就很简单了

  function load(chapter_info){    console.log(chapter_info.title)        $('title').html(chapter_info.title)    $('.chapter_title').html(chapter_info.title)    $('#content').load(type + '/' + book + '/' + chapter_info.url);  }

把章节.html加载到$(’#content’)里。

工具条

  <div class="bottem1">     <a href="javascript:;" class='pre_chapter_btn'>上一章</a> ←     <a href="javascript:;" class='chapter_btn'>章节列表</a> →     <a href="javascript:;" class='post_chapter_btn'>下一章</a>     <a href="javascript:;" class='bookmark'>加入书签</a>  </div> 

需要3个章节来切换状态

  • 上一章

  • 当前章节

  • 下一章

分别绑定事件

  //上一章  $('.pre_chapter_btn').on('click', function(){    console.log(pre_chapter_info)        load(pre_chapter_info)        addHistory(type, book, parseInt(chapter) - 1)  })    //章节列表  $('.chapter_btn').on('click', function(){    console.log(chapter_info)    window.scrollTo(0,0)  })    //下一章  $('.post_chapter_btn').on('click', function(){    console.log(post_chapter_info)        load(post_chapter_info)        addHistory(type, book, parseInt(chapter) + 1)  })

pushstate

其实这是h5的一个特性

// 增加历史记录
function addHistory(type, book, chapter){ history.pushState({"chapter":chapter}, '','/reader.html?type='+type+'&book='+book+'&chapter=' + chapter + '');  reset()  window.scrollTo(0,0)
}

history.pushState有3个参数

  • state

  • title

重置章节状态

在url变化的时候

function reset(){  type = getQueryStringByName('type')  book = getQueryStringByName('book')  chapter = getQueryStringByName('chapter')    pre_chapter_info    = current_book.chapters[parseInt(chapter) - 1]  chapter_info        = current_book.chapters[chapter]  post_chapter_info   = current_book.chapters[parseInt(chapter) + 1]
}

工具条是正文上下都有的,所以点击下面的,最好能够调回到顶部,故而当url变动的时候,需要滚动到顶部

  window.scrollTo(0,0)

收藏

HTML5 提供了两种在客户端存储数据的新方法:

  • localStorage - 没有时间限制的数据存储

  • sessionStorage - 针对一个 session 的数据存储

之前,这些都是由 cookie 完成的。但是 cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效率也不高。

在 HTML5 中,数据不是由每个服务器请求传递的,而是只有在请求时使用数据。它使在不影响网站性能的情况下存储大量数据成为可能。

对于不同的网站,数据存储于不同的区域,并且一个网站只能访问其自身的数据。 HTML5 使用 JavaScript 来存储和访问数据。

localStorage 方法存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。

  • get

  • set

  • remove

if(window.localStorage){  localStorage.setItem("b","isaac");//设置b为"isaac"  var b = localStorage.getItem("b");//获取b的值  localStorage.removeItem("c");//清除c的值}else{ alert('This browser does NOT support localStorage');
}

在chrome打开resource查看

这种k/v的存储,设计好key是非常重要的。

设置书key=0/330, 上次读到120章,每天url变动的时候设置,当用户主动点击的时候也可以重置。

使用http-server启动

$ npm i -g http-server $ hs dist -o

总结

只有1个reader.html就可以简化所有操作,还算是比较简单

涉及的知识点

  • ajax(getJSON和load)

  • on事件

  • h5里的pushstate和localstorage

这部分是完整的前端内容,所以单独讲解,即使是后端同学,应该也会比较容易理解。

 

演示:


本系列相关文章,会持续更新





全文完

如果想参与评论,请点击原文链接,进入国内最专业的cnode论坛

你身边如果有朋友对Node.js或全栈感兴趣,可以转发给他们看看哦



以上是关于实用前端Node.js写爬虫系列之第3章:编写小说阅读器的主要内容,如果未能解决你的问题,请参考以下文章

爬虫系列

爬虫系列之第3章-Selenium模块

一个用来爬小说的简单的NODE.JS爬虫

爬虫系列之第1章-简介&requests模块

爬虫系列之第2章-BS&Xpath模块

韦东山freeRTOS系列教程之第五章队列(queue)