NOTE The package nodespider is still under development. That means frequent changes and potential bug. So it is not suggested to using it in your project.
- 简单高效,开箱即用
- 自动识别网页编码格式,并将返回正文转码为utf8(可设置)
- 使用服务器端jQ选择器,轻松操作返回正文(可设置)
- 更轻松地保存抓取的数据(
pipe
和save
方法) - 轻松识别和过滤已经添加的链接(
isExist
和filter
方法) - 必要时,轻松可靠地重试某次请求任务(
retry
方法) - 轻松设置请求间隔、异步任务数。
- 独立管理不同的爬取策略与计划
- 支持 async function 和 promise
const { Spider, jsonPipe } = require("nodespider");
const n = new Spider({
rateLimit: 10
});
// 新建一个数据保存pipe
const jsonFile = n.pipe(jsonPipe("path/to/my.json"));
// 声明一个爬取计划
const planA = n.plan(function (err, current) {
if (err) {
// 如果出错,重试该任务,但最多3次
return n.retry(current, 3);
}
const $ = current.$; // 用JQ提取正文信息
console.log($("title").text());
// 保存从返回正文中提取的数据
n.save(jsonFile, {
user: $("#user").text(),
description: $("#desc").text(),
date: "2017-7-7",
})
});
// 添加链接到爬取队列
n.queue(planA, "https://www.nodejs.org");
npm install nodespider --save
const { Spider } = require("nodespider");
const n = new Spider();
// or
const nn = new Spider({
rateLimit: 20,
maxConnections: 20,
// or more
})
可选的设置:
设置 | 说明 | 类型 | 默认值 |
---|---|---|---|
rateLimit | 限速,网络请求的时间间隔(毫秒) | number | 2(毫秒) |
queue | 任务排队队列 | class | NodeSpider.Queue |
maxConnections | 最大同时连接限制 | number | object |
这个设置项用来设置爬虫的最大同时连接数,类型可以是number
或者object
。
当类型是number
此时表示,爬虫所有类型的同时连接的总数不能超过最大设置
const n = new Spider({
maxConnections: 10, // 最多同时执行10个异步连接任务
});
当类型是object
此时,你可以指定各种类型的最大同时连接数
const n = new Spider({
maxConnections: {
"download": 10, // 最多只能同时执行10个类型为"download"的异步连接任务
"crawl": 15,
}
});
NOTE: 注意,这时如果使用plan
新建一个type不存在于maxConnections
的计划,将会报错
在开始爬取前,你应该告诉爬虫你的爬取计划。例如,如何操作并提取返回正文的信息、你的爬取策略、请求时的header等。使用 plan
方法声明一个爬取计划,你可以详细描述你的爬取策略、请求设置、以及对返回的预处理。
参数 | 说明 | 类型 |
---|---|---|
item | 爬取策略函数或爬取策略 | function or object |
对当前爬虫声明一个爬取计划,并返回该计划的唯一标识符key(symbol, 用于方法 queue)。
const myPlan = n.plan(function (err, current) {
// your crawling rules
})
const otherPlan = n.plan({
request: {
method: "POST",
header: {
// some configs
}
// or more
},
pre: [],
callback: function (err, current) {
// your crawl rule
},
})
n.queue(otherPlan, "https://www.example.com");
nodespider自带两种plan: defaultPlan
和streamPlan
,具体文档可见plan.md.当你使用plan
方法并传递对象作为参数时,将默认使用defaultPlan
。
传入plan
的对象参数,对象成员有以下内容:
-
request (可选) 即该爬取计划的网络请求设置,将决定执行该计划时爬虫如何发出网络请求。通过设置你可以伪造ip、模拟登录、设置cookies、伪造浏览器标示等。具体设置可见 request文档
-
pre (可选) 该爬取计划的预处理列表。当成功请求到网页信息后,将对网页信息进行预处理。nodespider自带两个实用预处理函数:
preToUtf8
将网页内容自动转码为utf8格式,preLoadJq
对该网页内容加载JQ选择器(power by cheerio) -
info (可选) 对执行该计划的每一个任务附带信息对象。
info
将作为current
成员 -
callback (必须) 当报错或成功加载正文并预处理后,将调用callback。并传入两个参数
err
和current
。 你可以使用callback对爬到的网页进行的操作,比如提取信息、添加新的链接到排队列表……
callback
函数在执行时将传入两个参数:error
和current
。其中current
对象包含了很多当前任务的信息:
- url 当前任务的链接
- planKey 当前任务指定计划的key
- response 请求回应
- body 返回正文
- error 任务执行中的错误(等价于rule函数error参数)
- info 当前任务附带的信息
- maxRetry (可能不存在)当前任务的最大重试次数限制
- hasRetried (可能不存在)当前任务已经重试的次数
- and more ... 以及可能的更多成员属性
NOTE 值得注意的是,当前任务的指定计划,或者是特定设置中的预处理函数,往往会修改current
中的成员属性,甚至添加更多的成员属性。
添加链接到队列,并指定对应的爬取计划。 所有添加到队列的链接,将排队等待抓取工作。
设置 | 说明 | 类型 |
---|---|---|
planKey | 该任务指定计划的key(由plan 方法生成) |
symbol |
url | 需要排队的链接 | string or array |
special | (可选) 该任务特有的计划设置(将在爬取过程中覆盖指定计划的执行) | Object |
const n = new Spider();
const myPlan = n.plan(function (err, current) {
// some crawling rules
});
n.queue(myPlan, "https://en.wikipedia.org");
n.queue(myPlan, [
"http://www.github.com",
"https://stackoverflow.com/",
"https://nodejs.org"
]);
重试某项任务
参数 | 说明 | 类型 |
---|---|---|
task | 需要重试的当前任务 | object |
maxRetry | (可选)该任务的最大重试数目(最多重复多少次)。默认: 1 | number |
finalErrorCallback | (可选)达到最大重试数目时调用的函数 | function |
const myPlan = n.plan(function (err, current) {
if (err) {
return n.retry(current);
}
});
const otherPlan = n.plan(function (err, current) {
if (err) {
// 如果出现错误,重试当前任务,但最多不超过10次
return n.retry(current, 10);
}
});
const anotherPlan = n.plan(function (err, current) {
if (err) {
// 如果出现错误,重试当前任务,但最多不超过5次
return n.retry(current, 5, (current) => {
// 当重复次数达到五次时,调用回调函数
console.log(current.url);
})
}
});
检查是否添加过某个链接
参数 | 说明 | 类型 |
---|---|---|
url | 需要检测是否存在的url | string |
return | 说明 |
---|---|
boolean | 若该链接已经添加过,则返回true |
n.queue(myPlan, "http://www.example.com");
n.isExist("http://www.example.com"); // True
过滤掉一个数组中的重复链接,以及所有已被添加的链接,返回一个新数组
参数 | 类型 |
---|---|
urls | array (of string) |
return |
---|
array |
return type: array
n.queue(planA, "http://a.com");
var i = n.filter(["http://a.com", "http://b.com", "http://c.com"]);
console.log(i); // ["http://b.com", "http://c.com"]
var j = n.filter(["http://a.com", "http://aa.com", "http://aa.com"]);
console.log(j); // ["http://aa.com"]
使用方法 pipe 和 save,可以方便地保存抓取的数据。
在当前实例注册一个pipe,并返回对应的key(用于 save 方法)。
参数 | 说明 | 类型 |
---|---|---|
pipeGenerator | pipe生成器新建的对象 | object |
const { Spider, jsonPipe, txtPipe } = require("nodespider");
const n = new Spider();
const txtPipe = n.pipe(jsonPipe("save/my.json"));
n.save(txtPipe, {
name: "ben",
age: 20,
});
nodespider 自带了两个pipe建立函数:jsonPipe
和txtPipe
,可以帮助开发者以json格式或txt表格形式来储存提取的数据,在下文中有更多介绍。
保存数据到指定pipe
参数 | 说明 | 类型 |
---|---|---|
pipeKey | 指定pipe的key,由 pipe 方法生成 |
symbol |
data | 需要保存的数据 | object |
const myJson = n.pipe(jsonPipe("save_path/my.json"));
const planA = n.plan(function (err, current) {
if (err) {
return n.retry(current);
}
const $ = current.$;
// 保存抓取的数据到本地 my.json 文件
n.save(myJson, {
name: $("#name").text(),
age: $("#age").text(),
description: $("#desc").text(),
});
})
nodespider自带了两个pipe发生器:jsonPipe
和txtPipe
,可以帮助开发者保存提取的数据到本地。
const {Spider, jsonPipe, txtPipe} = require("nodespider");
数据将以json形式保存到本地
参数 | 类型 | 说明 |
---|---|---|
path | string | 保存文件路径 |
space | number | (可选)缩进空格数 |
const myJson = n.pipe(jsonPipe("path/to/my.json"));
const myPlan(function (err, current) {
const $ = current.$;
n.save(myJson, {
name: $("#name").text(),
desc: $("#desc").text(),
})
})
数据将以txt表格形式写入(由制表符和换行符隔开)。
参数 | 类型 | 说明 |
---|---|---|
path | string | 保存文件路径 |
header | array | 表头元素数组 |
const txt = n.pipe(txtPipe("path/to/my.txt", ["name", "description"]));
n.save(txt, {
name: "some data",
description: "example"
})
nodespider 自带了两个预处理函数:preToUtf8
, preLoadJq
,可以帮助开发者的快速解决很多常见问题。
根据网页信息,自动将爬取正文转码为utf8格式。即将current.body
修改为utf8格式。
const { Spider, preToUtf8 } = require("nodespider");
const newPlan = n.plan({
pre: [
preToUtf8()
],
rule: (err, current) => {
console.log(current.body);
}
})
解析current.body
并加载服务器端jQ选择器(power by bycheerio),并添加current.$
成员。利用选择器,你可以非常方便的从返回正文中提取信息
const justPlan = n.plan({
pre: [
preToUtf8(),
preLoadJq(),
],
rule: (err, current) => {
const $ = current.$;
console.log($("title").text());
}
});
nodespider是一个开源爬虫package,主旨是让爬虫开发更简单、更灵活、模块化、更具扩展性。为了变得更好,nodespider需要更多人的贡献,包括但不限于: