nodejs cheerio模块提取html页面内容

本文给出使用一个用cheerio模块提取html文件中指定内容的例子,并说明具体步骤、涉及到的API、以及其它模块。 cheerio模块是一个类似jquery的模块,具有相似的API、功能,能够将一个网页解析为DOM,以及通过selector选择元素,设置、获取元素属性。

以下为我们待解析网页截图:

目标是将task1-5中的所有题目、以及答案提取出来,以文本形式保存。最终提取出的效果如下。 这是题目文本:

Task 1: You will be given 10 minutes to read the text for the first time and then choose an appropriate answer for each of the following questions.

1. What’s the passage mainly about?
A. How to learn online successfully.
B. How to set up a learning goal.
C. The future of online learning.
D. The benefits of online learning. ...

这是答案文本:

Task 1:
1. D
2. C
3. C
4. D
5. A

注:其中答案保存在网页中,但在网页中没有显示出来。

1.1 找到目标元素

提取问题文本的整体思路:先找到包含题目的所有元素,然后再获取这些元素的内容即可。 通过chrome的devtool(或者firefox的firebug)看出,所有的目标元素为:hr元素的所有兄弟结点。cheerio的nextAll函数满足需求,这个函数获取当前结点的所有后续的兄弟结点。程序如下:

 
var fs = require('fs');
var cheerio = require('cheerio'); var myHtml = fs.readFileSync("a.html");
var $ = cheerio.load(myHtml);
var t = $('html').find('hr');
var t2 = t.nextAll(); t2.each(function(i, elem) {
getContent($(this));
console.log($(this).text());
});

首先将网页读取为一个字符串,传给cheerio.load函数,返回值即是一个cheerio对象(类似于一个jquery对象)。然后使用find函数,通过selector查找hr元素。再调用 nextAll函数得到hr元素的所有兄弟结点。 最后在each函数中, 通过text函数将所有包含问题的元素的见容打印出来。

结果中有乱码,问题原因是fs模块不支持中文。通过iconv-lite先解码为中文解决。修改后代码如下:

var fs = require('fs');
var cheerio = require('cheerio');
var iconv = require('iconv-lite'); var myHtml = fs.readFileSync("a.html");
var $ = cheerio.load(iconv.decode(myHtml, 'gbk'));
var t = $('html').find('hr');
var t2 = t.nextAll(); t2.each(function(i, elem) {
getContent($(this));
console.log($(this).text());
});

最终结果如下:

           Task  1: You will be given 10 minutes to read the text for the first time and then
                         choose an appropriate answer for each of the following questions.  1. What does the “true gratitude” mean?
     A. A way of life.
    
B. A joyous occasion.
    
...

以上结果有多余的空格、换行符,输出文本看起来很散乱,但至少内容是获取正确了。再在task2-5的html文件验证一下,也获取到了正确的内容,证明方法可行。接下来我们可以集中精力解决格式散乱的问题。

1.2 美化文本输出

最主要的问题是有多余的空格、换行符。想到的一个办法是:将所有结点的内容(包括文本结果)trim,即去年前后的所有空白字符,并对于br元素,加入一个换行符。也即模拟了一下html文档的render效果(因为在浏览器中显示是正确的,所以采用同样的方法,也能得到相同的结果)。 要实现这个方法,要获取一个元素的所有的子结果,使用cheerio的contents函数,这个函数获取一个元素的所有子元素(包括文本元素)。然后调用字符串的trim函数去除首尾的空白文本。由于子元素又有子元素,因此使用递归函数。代码如下:

function getContent(node){
var a = node.contents();
if (a.length == 0) {
if (node.is('br')){
RST+='\n';
} else {
RST+=node.text().trim();;
}
} else {
node.contents().each(function(i, elem){
getContent($(this));
}); if (node.is('p') || node.is('tr')){
RST+='\n';
}
}
}

getContent函数用于获取一个元素的文本内容,输入参数为元素,这个函数会被递归调用。首先调用contents函数获取所有子元素。如果子元素数目为0,表示这个元素是叶结点,则首先判断如果是br元素,则在结果中加入一个换行符,否则,调用text函数获取这个元素的文本内容。 如果子元素大于0,则递归地处理所有子元素。如果当前元素为p或tr元素,则在结果中加入一个换行。 其中RST为一个全局变量,用于保存结果文本。在调用函数前需要设置为空字符串。 这样处理后,结果如下:

Task  1: You will be given 10 minutes to read the text for the first time and then
choose an appropriate answer for each of the following questions.
1. What does the “true gratitude” mean?
A.A way of life.
B.A joyous occasion.
C.A much deeper level of gratitude.
D.The improvement of the quality of life.
2. Who has so many things to be grateful for?
...

看起来漂亮多了。 问题文本提取成功,接下来再提取答案文本。

1.3 提取答案文本

在html源文件中搜索answer,可以看出,答案是保存在script中的,如下:

<SCRIPT LANGUAGE="JavaScript">
var StandardAnswer = new Array()
StandardAnswer =["C","D","D","D","D"]
</SCRIPT>

选择题的答案保存在StandardAnswer的数组中。则获取答案文本的方法为:先获取script元素中的代码文本,再通过eval函数得到这个数组值,最后生成答案文本。代码如下:

var t = $('html').find('script');
var A = undefined;
t.each(function(i, elem) {
var text = $(this).text();
if (text.match('StandardAnswer')){
var a = eval(text);
console.log("standardanswer: "+ a);
A= a;
}
});

变量A保存答案数组。通过判断文本中是否包含'StandardAnswer'来判断是否是目标代码。然后将这个代码传给eval,返回值即为‘["C","D","D","D","D"]‘这个数组。 有了答案数组,生成答案文本就比较容易了。

1.4 最终代码

可以在这查看最终代码。 最终的代码还解决了一些小问题,如问题文本中包含了多余的文本(对于task4),task4的答案也会被显示在问题文本中,没有留下空白填写答案等。 整个分析、编码过程大致3个小时。其中文件a.js用于生成问题文本,b.js用于生成答案文本。a.js与b.js有很大的重复(b.js是直接复制了一份a.js修改而来)。这个代码基本上是解决一次性问题,没有什么重用性(在编写的过程中也没有考虑这些)。但是最重要的是:它解决了问题,它能够工作。它不需要那么好!最后,这个程序被用于处理几十个文件,成功正确地生成了问题文本及答案文本。

nodejs cheerio模块提取html页面内容的更多相关文章

  1. [实战演练]python3使用requests模块爬取页面内容

    本文摘要: 1.安装pip 2.安装requests模块 3.安装beautifulsoup4 4.requests模块浅析 + 发送请求 + 传递URL参数 + 响应内容 + 获取网页编码 + 获取 ...

  2. 【java】抓取页面内容,提取链接(此方法可以http get无需账号密码的请求)

    package 网络编程; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileOutpu ...

  3. 今天用node的cheerio模块做了个某乎的爬虫

        一时兴起,想做个爬虫,经过各种深思熟虑,最后选择了某乎,毕竟现在某乎的数据质量还是挺高的.说干就干 打开某乎首页,随便搜索了一串关键字,相关的问题和答案就展现在眼前,我就思考怎么把这些搜索结果 ...

  4. 基于Metronic的Bootstrap开发框架经验总结(9)--实现Web页面内容的打印预览和保存操作

    在前面介绍了很多篇相关的<Bootstrap开发框架>的系列文章,这些内容基本上覆盖到了我这个Bootstrap框架的各个主要方面的内容,总体来说基本达到了一个稳定的状态,随着时间的推移可 ...

  5. NodeJS Web模块

    NodeJS Web模块 本文介绍nodeJS的http模块的基本用法,实现简单服务器和客户端 经典Web架构 Client:客户端一般指浏览器,通过HTTP协议向服务器发送请求(request) S ...

  6. web 页面内容优化管理与性能技巧

    回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起,我 ...

  7. 在Bootstrap开发框架的前端视图中使用@RenderPage实现页面内容模块化的隔离,减少复杂度

    在很多开发的场景中,很多情况下我们需要考虑抽象.以及模块化等方面的内容,其目的就是为了使得开发的时候关注的变化内容更加少一些,整体开发更加简单化,从而减少开发的复杂度,在Winform开发的时候,往往 ...

  8. 【新手向】使用nodejs抓取百度贴吧内容

    参考教程:https://github.com/alsotang/node-lessons 1~5节 1. 通过superagent抓取页面内容 superagent .get('http://www ...

  9. python操作三大主流数据库(5)python操作mysql⑤使用Jinja2模板提取优化页面展示

    python操作mysql⑤使用Jinja2模板提取优化页面展示 在templates目录下的index.html.cat.html等页面有一些共同的元素,代码比较冗余可以使用模板提取公共代码,在各网 ...

随机推荐

  1. centos7开机启动tomcat7

    1.进入tomcat/bin vi setenv.sh      (原来没有这个文件,需要创建出来) 添加 #add tomcat pid CATALINA_PID="$CATALINA_B ...

  2. MySQL给字段唯一索引的三种方法

    建表时添加 DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `stu_id` ) NOT NULL AUTO_INCREMENT, ` ...

  3. Maven学习笔记—私服(包含maven的setting.xml配置)

    为什么要用远程仓库(私服) 如果没有私服,我们所需的所有构件都需要通过maven的中央仓库和第三方的maven仓库下载到本地,而一个团队中的所有人都重复的从maven仓库下载构件,这样就加大了中央仓库 ...

  4. 维多利亚的秘密 golang入坑系列

    原文在gitbook,字字原创,版权没有,转载随意. 在写本文的前一天,2017维密在上海开始了. 为了纪念屌丝界的盛世,特为本节起名维多利亚的秘密.现在的社会,要想出名只有抓眼球.所以写份技术文章, ...

  5. App doesn't auto-start an app when booting the device in Android

    From Android 3.1, newly installed apps are always put into a "stopped" state and the only ...

  6. zz Qt下 QString转char*和char []

    以下内容为转载:http://www.cnblogs.com/Romi/archive/2012/03/12/2392478.html -------------------------------- ...

  7. JetBrains ReSharper 8.2 Build 8.2.0.2160 && StyleCop

    先安装 StyleCop 再安装 JetBrains ReSharper 8.2 Build 8.2.0.2160

  8. pandas(九)数据转换

    移除重复数据 dataframe中常常会出现重复行,DataFrame对象的duplicated方法返回一个布尔型的Series对象,可以表示各行是否是重复行.还有一个drop_duplicates方 ...

  9. DBMS_MONITOR程序开启10046事件

    在具有连接池或共享服务器的多层环境中,一个会话可以跨越多个进程,甚至跨越多个实例.DBMS_MONITOR是在Oracle 10g中引入的内置的程序包,通过该程序包可以跟踪从客户机到中间层.再到后端数 ...

  10. Ubuntu学习笔记1-基本部分

    Vim相当于vi的升级版 Find p*.txt支持查找通配符 Echo 回显命令 echo hello  >1.txt  追加命令,不覆盖 echo hello  >1.txt  覆盖命 ...