由于最近要实现一个爬取H5游戏的代理服务器,隧看到这么一篇不错的文章(http://blog.miguelgrinberg.com/post/easy-web-scraping-with-nodejs),加之最近在学习Node.js,所以就准备翻译出来加深一下印象。

转载请注明来源:(www.cnblogs.com/xdxer

 

在这篇文章中,我将会向大家展示如何用JavaScript配合Node.js写一个网络爬取的脚本。

网络抓取工具

在大部分情况下,一个网络抓取的脚本只需要一种方法去下载整个页面,然后搜索里面的数据。所有的现代语言都会提供方法去下载网页,或者至少会有人实现了某个library或者一些其他的扩展包,所以这并不是一个难点。然后,要精确定位并且找出在HTML中的数据是比较有难度的。一个HTML页面混杂了许多内容、布局和样式的变量,所以去解释并且识别出那些我们关注的部分是一个挺不容易的工作。

举个例子,考虑如下的HTML页面:

<html>
<head>...</head>
<body>
<div id="content">
<div id="sidebar">
...
</div>
<div id="main">
<div class="breadcrumbs">
...
</div>
<table id="data">
<tr><th>Name</th><th>Address</th></tr>
<tr><td class="name">John</td><td class="address">Address of John</td></tr>
<tr><td class="name">Susan</td><td class="address">Address of Susan</td></tr>
</table>
</div>
</div>
</body>
</html>

如果我们需要获取到出现在 id = “data”这个表中的人名,那么应该怎么做呢?

一般的,网页会被下载成一个字符串的形式,然后只需要很简单的对这个网页进行检索,检索出那些出现在<td class = “name”> 之后,以</td>结尾的字符串就可以了。

但是这种方式很容易会获取到不正确的数据。网页可能会有别的table,或者更加糟糕的是,原先的<td class="name"> 变成了 <td align="left" class="name"> ,这将会让我们之前所制定的方案什么都找不到。虽然说网页的变化很容易导致一个爬取脚本失效,但是假如我们可以清楚的知道元素是如何在HTML中组织的,那么我们就不必总是重写我们的爬取脚本,当网页改变的时候。

如果你写过前端的js代码,使用过jQuery,那么你就会发现使用CSS selector 来选择DOM中的元素是一件非常简单的事情。举个例子,在浏览器中,我们可以很简单的爬取到那些名字使用如下的方式:

$('#data .name').each(function() {
alert($(this).text());
});

 

介绍一下Node.js

http://nodejs.org (get it here!)

Javascript 是一个嵌入web浏览器的语言,感谢Node.js工程,我们现在可以编写能够独立运行,并且甚至可以作为一个web server 的编程语言。

有很多现成的库,例如jQuery那样的。所以使用Javrscript+Node.js去实现这么一个任务就非常便利了,因为我们可以使用那些现有的操作DOM元素的技术,这些技术在web浏览器上已经应用的比较成熟了。

Node.js有很多的库,它是模块化的。本例子中需要用到两个库,request 和 cheerio。 request主要是用于下载那些网页,cheerio 会在本地生成一棵DOM树,然后提供一个jQuery子集去操作它们。安装Node.js模块需要用到npm操作,类似于Ruby的gem 或者 Python的easy_install

有关于cheerio的一些API 可以参考这一篇CNode社区的文章 (https://cnodejs.org/topic/5203a71844e76d216a727d2e

$ mkdir scraping
$ cd scraping
$ npm install request cheerio

如以上代码所示,首先我们创建了一个目录“scraping”,并且我们在在这个目录下安装了request 和 cheerio模块,事实上,nodejs的模块是可以进行全局性的安装的,但是我更加喜欢locally的安装,安装的效果如下图所示。

那接下来我们就看看如何使用cheerio,来爬取上面的例子中的name,我们创建一个.js文件 example.js,代码如下:

var cheerio = require('cheerio');
$ = cheerio.load('<html><head></head><body><div id="content">
<div id="sidebar"></div><div id="main">
<div id="breadcrumbs"></div><table id="data"><tr>
<th>Name</th><th>Address</th></tr><tr><td class="name">
John</td><td class="address">Address of John</td></tr>
<tr><td class="name">Susan</td><td class="address">
Address of Susan</td></tr></table></div></div></body></html>');

$('#data .name').each(function() {
console.log($(this).text());
});

输出如下:

$ node example.js
John
Susan

实际例子

http://www.thprd.org/schedules/schedule.cfm?cs_id=15 爬取这个网站中的日程表

代码如下:

var request = require('request');
var cheerio = require('cheerio'); days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
pools = {
'Aloha': 3,
'Beaverton': 15,
'Conestoga': 12,
'Harman': 11,
'Raleigh': 6,
'Somerset': 22,
'Sunset': 5,
'Tualatin Hills': 2
};
for (pool in pools) {
var url = 'http://www.thprd.org/schedules/schedule.cfm?cs_id=' + pools[pool]; request(url, (function(pool) { return function(err, resp, body) {
$ = cheerio.load(body);
$('#calendar .days td').each(function(day) {
$(this).find('div').each(function() {
event = $(this).text().trim().replace(/\s\s+/g, ',').split(',');
if (event.length >= 2 && (event[1].match(/open swim/i) || event[1].match(/family swim/i)))
console.log(pool + ',' + days[day] + ',' + event[0] + ',' + event[1]);
});
});
}})(pool));
}

输出如下:

$ node thprd.js
Conestoga,Monday,4:15p-5:15p,Open Swim - M/L
Conestoga,Monday,7:45p-9:00p,Open Swim - M/L
Conestoga,Tuesday,7:30p-9:00p,Open Swim - M/L
Conestoga,Wednesday,4:15p-5:15p,Open Swim - M/L
Conestoga,Wednesday,7:45p-9:00p,Open Swim - M/L
Conestoga,Thursday,7:30p-9:00p,Open Swim - M/L
Conestoga,Friday,6:30p-8:30p,Open Swim - M/L
Conestoga,Saturday,1:00p-4:15p,Open Swim - M/L
Conestoga,Sunday,2:00p-4:15p,Open Swim - M/L
Aloha,Monday,1:05p-2:20p,Open Swim
Aloha,Monday,7:50p-8:25p,Open Swim
Aloha,Tuesday,1:05p-2:20p,Open Swim
Aloha,Tuesday,8:45p-9:30p,Open Swim
Aloha,Wednesday,1:05p-2:20p,Open Swim
Aloha,Wednesday,7:50p-8:25p,Open Swim
Aloha,Thursday,1:05p-2:20p,Open Swim
Aloha,Thursday,8:45p-9:30p,Open Swim
Aloha,Friday,1:05p-2:20p,Open Swim
Aloha,Friday,7:50p-8:25p,Open Swim
Aloha,Saturday,2:00p-3:30p,Open Swim
Aloha,Saturday,4:30p-6:00p,Open Swim
Aloha,Sunday,2:00p-3:30p,Open Swim
Aloha,Sunday,4:30p-6:00p,Open Swim
Harman,Monday,4:25p-5:30p,Open Swim*
Harman,Monday,7:30p-8:55p,Open Swim
Harman,Tuesday,4:25p-5:10p,Open Swim*
Harman,Wednesday,4:25p-5:30p,Open Swim*
Harman,Wednesday,7:30p-8:55p,Open Swim
Harman,Thursday,4:25p-5:10p,Open Swim*
Harman,Friday,2:00p-4:55p,Open Swim*
Harman,Saturday,1:30p-2:25p,Open Swim
Harman,Sunday,2:00p-2:55p,Open Swim
Beaverton,Tuesday,10:45a-12:55p,Open Swim (No Diving Well)
Beaverton,Tuesday,8:35p-9:30p,Open Swim No Diving Well
Beaverton,Thursday,10:45a-12:55p,Open Swim (No Diving Well)
Beaverton,Thursday,8:35p-9:30p,Open Swim No Diving Well
Beaverton,Saturday,2:30p-4:00p,Open Swim
Beaverton,Sunday,4:15p-6:00p,Open Swim
Sunset,Tuesday,1:00p-2:30p,Open Swim/One Lap Lane
Sunset,Thursday,1:00p-2:30p,Open Swim/One Lap Lane
Sunset,Sunday,1:30p-3:00p,Open Swim/One Lap Lane
Tualatin Hills,Monday,7:35p-9:00p,Open Swim-Diving area opens at 8pm
Tualatin Hills,Wednesday,7:35p-9:00p,Open Swim-Diving area opens at 8pm
Tualatin Hills,Sunday,1:30p-3:30p,Open Swim
Tualatin Hills,Sunday,4:00p-6:00p,Open Swim
要注意的几个问题: 异步js的作用域问题,还有对网站结构的分析,我会在其他博客中提到。
其实我只翻译了很少的一部分,有兴趣的可以去看一下原文,每一步都说的很仔细。

使用Node.js实现简单的网络爬取的更多相关文章

  1. Centos7 中 Node.js安装简单方法

    最近,我一直对学习Node.js比较感兴趣.下面是小编给大家带来的Centos7 中 Node.js安装简单方法,在此记录一下,方便自己也方便大家,一起看看吧! 安装node.js 登陆Centos ...

  2. 创建node.js一个简单的应用实例

    在node.exe所在目录下,创建一个叫 server.js 的文件,并写入以下代码: //使用 require 指令来载入 http 模块 var http = require("http ...

  3. Java两种方式简单实现:爬取网页并且保存

    注:如果代码中有冗余,错误或者不规范,欢迎指正. Java简单实现:爬取网页并且保存 对于网络,我一直处于好奇的态度.以前一直想着写个爬虫,但是一拖再拖,懒得实现,感觉这是一个很麻烦的事情,出现个小错 ...

  4. pyhton 网络爬取软考题库保存text

    #-*-coding:utf-8-*-#参考文档#https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#find-al ...

  5. 使用requests简单的页面爬取

    首先安装requests库和准备User Agent 安装requests直接使用pip安装即可 pip install requests 准备User Agent,直接在百度搜索"UA查询 ...

  6. Node.js实现简单的爬取

    学习[node.js]也有几天时间了,所以打算写着练练手:索然我作为一个后端的选手,写起来还有那么一丝熟悉的感觉.emmm~~  ‘货’不多讲 ,开搞........ 首先是依赖选择: 代码块如下: ...

  7. Nodejs入门-基于Node.js的简单应用

    服务端JavaScript 众所周知的,JavaScript是运行在浏览器的脚本语言,JavaScript通常作为客户端程序设计语言使用,以JavaScript写出的程序常在用户的浏览器上运行.直至N ...

  8. 用node.js实现简单的web服务器

    node.js实现web服务器还是比较简单的,我了解node.js是从<node入门>开始的,如果你不了解node.js也可以看看! 我根据那书一步一步的练习完了,也的确大概了解了node ...

  9. Node.js 实现简单小说爬虫

    最近因为剧荒,老大追了爱奇艺的一部网剧,由丁墨的同名小说<美人为馅>改编,目前已经放出两季,虽然整部剧槽点满满,但是老大看得不亦乐乎,并且在看完第二季之后跟我要小说资源,直接要奔原著去看结 ...

随机推荐

  1. linux下脚本监控网络流量

    linux下脚本监控网络流量 学习了:https://blog.csdn.net/chenghuikai/article/details/48437479 学习了:http://www.jb51.ne ...

  2. 关于SharePoint 讨论板的一些知识

    关于SharePoint 讨论板的一些知识         近期公司项目可能要用到讨论板.需求是这种:         怎样在回复中仅仅让查看登陆者和讨论主题公布者的信息.         比方我公布 ...

  3. 用ELK 实时处理搜索日志

    转载请标明原处:http://blog.csdn.net/hu948162999/article/details/50563110 本来这块业务 是放到SolrCloud上去的 , 然后 採用solr ...

  4. 英特尔和Red Hat合作实现Gnome桌面的Wayland支持

    在发布支持XMir的Linux图形驱动程序xf86-video-intel 2.99.901后数天,英特尔宣布撤回对XMir的支持,XMir补丁不会合并到上游项目.XMir是Mir显示服务器的X11兼 ...

  5. linux下nginx+php+mysql 自助环境搭建

    ++++++++++++++++++++++++++++++++++++++++++++++linux下nginx+php+mysql环境搭建+++++++++++++++++++++++++++++ ...

  6. LeetCode:二叉树的非递归中序遍历

    第一次动手写二叉树的,有点小激动,64行的if花了点时间,上传leetcode一次点亮~~~ /* inorder traversal binary tree */ #include <stdi ...

  7. EasyDarwin开源流媒体云平台之EasyRMS录播服务器功能设计

    需求背景 EasyDarwin开发团队维护EasyDarwin开源流媒体服务器也已经很多年了,之前也陆陆续续尝试过很多种服务端录像的方案,有:在EasyDarwin中直接解析收到的RTP包,重新组包录 ...

  8. EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传

    本文转自EasyDarwin团队成员Alex的博客:http://blog.csdn.net/cai6811376 EasyCamera开源摄像机拥有获取摄像机实时快照并上传至EasyDarwin云平 ...

  9. mysql的事务隔离级别及其使用场景

    1 什么是事务隔离级别 事务隔离指的是事务之间同步关系. 2 食物隔离级别的分类 第一隔离级别,脏读级别 在脏读级别下,第一个事务修改了某个数据,但是还没有提交,第二个事务可以读取到这个未提及的数据. ...

  10. JBPM工作流简单步骤

    启动流程: 获取最新的流程定义: JbpmContext.getCurrentJbpmContext().getGraphSession().findLatestProcessDefinitions( ...