由于闲暇时间会看电子书小说,一时心血来潮,想搞个电子书爬虫,于是阅读了下 nodejs 官网文档,并未深究,做了个电子书爬虫与 kindle 自动推送的网站,供自己使用
写这篇文章就是想记录下自己是怎么一步一步完善这个网站功能的,使用到的技术很普通:nodejs、jq,做的也很粗糙,够自己使用,网址:http://book.ln26.net,效果如下
-
实现思路
_思路是挺重要的,做程序就是这样,我也是一时心血来潮,所以在开始这个项目前,我也是完全没有 nodejs 的开发经验的,但是 js 的一些基础还是要有的
核心思路:
1、html 提供书名输入
2、nodejs 搭建服务器,根据书名去电子书网站爬取内容
3、把关键下载地址爬下来,供下载与 kindle 推送
4、实现下载文件
5、实现压缩包的文件解压(部分电子书网站提供 zip 的下载)
6、实现邮件发送(因为 kindle 的推送基于邮件发送)
7、删除下载的文件
整体说来就是利用 nodejs 服务,把电子书下载下来,zip 的包就解压缩,拿到里面的 电子书.txt,然后自动发送邮件带上电子书.txt 的附件,发送到 kindle 绑定的邮箱 ,下面介绍我是怎么一步步完成的
-
一步步完成
1、html 的输入部分,没有什么特别的,使用 jq 获取表单上的用户输入,然后把搜索的关键字传给 nodejs 服务搭建的接口上
2、nodejs 搭建服务器,这一步开始,就是我自己的探索过程:
在nodejs官网上下载好node,安装好最新版本,轻轻松松,然后开始搭建第一个应用,在网上搜索了一番,推荐使用 Express,于是又跑到 Express,看了下入门和创建应用服务
$ npm install express --save // 安装好 express
创建一个简单的应用 test-node.js
var express = require('express');
var app = express();
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function(req, res) {
res.send('hello world');
});
app.listen(8888);
在 test-node.js 的目录下执行
node test-node.js // 启动
在浏览器上打开 http://localhost:8888 能看到 hello world 就说明启动成功了,依旧是轻轻松松,跟着文档走
接下来就是爬虫的编写了,网上看了下别人的简单例子,推荐使用 superagent,于是就看了下 superagent 的使用
$ npm install superagent --save // 安装好 superagent
var superagent = require('superagent');
var url = 'http://zhannei.baidu.com/cse/search?searchtype=complex&q=123&s=18140131260432570322'; // 一个接受 get 请求的电子书网站
// 一个简单的 get 请求
superagent.get(url)
.end(function (err, res) {
// 常规的错误处理
if (err) {
console.log(err);
}
// 网页的抓取内容都在 resr 的 body 里面
console.log(res);
});
// 一个简单的 post 请求
superagent
.post(url)
.type('form') // 参数转化为 form data 的格式
.send({key: 123}) // 参数
.end(function(err, res) {
// 常规的错误处理
if (err) {
console.log(err);
}
console.log(res);
})
上面的例子都是我用到的简单的请求,我这里只讲我自己的做法,比较简单粗糙,想了解具体可以去看看相关文档
3、把关键下载地址爬下来,供下载与 kindle 推送
因为我是需要去爬相应的电子书,所以我的做法是在网上随便找个电子书网站,在上面找到搜索电子书的地方,随便输入然后点击搜索,就会跳转到相应的搜索页,打开调试面板找到这个页面的数据来源,用 superagent 模拟搜索页的请求,就能获取相应的页面内容了
拿到页面请求之后的处理
网上看到部分是在 nodejs 里处理,由于我是个人网站,不想增加服务器压力,就放到了客户端处理,简单来说:我把拿到的数据,返回到客户端,用 jq 提取中间的下载地址,但是电子书网站都会放广告,需要一直往里跳转,才能找到 电子书.txt 的下载地址,所以我做了一个递归查询,从找到的第一个下载地址一直往里爬,直到找到真正的下载地址为止。
甚至更简单的做法:
针对某个电子书网站进行爬取,这样就知道往里跳几次就能拿到真正的 电子书.txt 的地址,用 superagent 往里多搜索几次直到拿到 电子书.txt 的地址,用 jq 把 <a> 标签都取出来,塞到自己html 里,这样就能做到点击下载了
4、实现下载文件
拿到下载地址就 OK 了,利用下载地址把文件下载下来,又一顿百度大法,推荐 fs 文件操作模块,安装 fs 模块 与 request 模块
$ npm install fs --save
$ npm install request --save
文件下载操作
var fs = require('fs');
var request = require('request');
let name = Date.now() + '.txt'; // 自定义文件名称
let file = __dirname + '/' + name; // 文件绝对地址
let stream = fs.createWriteStream(file); // 创建文件
let url = 'https://dt.80txt.com/1567/无敌黑枪.txt'; // 电子书的下载地址
// 把电子书下载下来,写入到创建的文件
request(url).pipe(stream).on("close", function (err) {
console.log('下载成功');
});
在目录下能看到一个 .txt 文件就说明下载成功啦
5、实现压缩包的文件解压
上面例子用到的下载文件是 txt ,但是一般的电子书网站都会提供 zip 的压缩包下载,所以还需要解压缩。还是百度大法,推荐了 adm-zip
$ npm install adm-zip --save
安装好之后
var adm_zip = require('adm-zip');
var fs = require('fs');
var url = __dirname + '/123.zip'; // 当前目录下的 123.zip 文件
var name = Date.now() + '.txt'; // 解压后的文件名称
var unzip = new adm_zip(url); // 解压
var files = unzip.getEntries()[0].entryName; // 获取到压缩包里的文件名称
unzip.extractAllTo(__dirname); // 解压到当前目录
// 重命名压缩包里面的文件
fs.rename(__dirname + '/' +files, __dirname + '/' + name,
function(err){
if(err){
console.log("重命名失败");
}else{
console.log("解压成功");
// 解压成功后删除压缩包
fs.unlink(url, function (err) {
if(err) throw err;
console.log(url + '删除成功')
});
}
});
6、实现邮件发送
还是通过网上搜索,推荐使用 nodemailer 模块
npm install nodemailer --save
npm install nodemailer-smtp-transport --save
直接上代码
var fs = require('fs');
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
// 邮箱
var email = {
service: '163',
user: '136xxxxxxxx@163.com',
pass: 'xxxxx', // 授权码
};
var config = {
email
};
smtpTransport = nodemailer.createTransport(smtpTransport({
service: config.email.service,
auth: {
user: config.email.user,
pass: config.email.pass
}
}));
// 发送邮件
var file = './123.txt'; // 下载下来的 txt 文件的地址
smtpTransport.sendMail({
from: config.email.user,
to: 'xxx@kindle.cn',
subject: '123.txt',
html: '123.txt',
attachments:[
{
filename : '123.txt',
path: file // 下载下来的 txt 文件的地址
}
]
}, function (error, response) {
if (error) {
console.log('error', error);
}
// 发送后后删除 txt
fs.unlink(file, function (err) {
if(err) throw err;
console.log(file + '删除成功')
});
console.log('success');
});
发送邮件的代码不是很复杂,但是这里有几个点,必须要 注意:
1、邮件名称、邮件内容、附件名称、附件地址里面的文件名称,最好一致,这里有一个坑,如果不一致,kindle 那边有时会说附件出问题
2、里面我用的163邮箱,至于里面怎么设置,去网上查下『163邮箱如何开启 SMTP 服务』就好
3、163邮箱 常规设置 写信设置 附件上传方式 设置为标准模式
4、要让 kindle 的信任邮箱里,添加你用于推送附件的163邮箱
注:这里我使用的163邮箱,你们可以随意
7、删除下载的文件
上面的代码里已经提到了
var fs = require('fs');
var file = './123.txt'; // 文件地址
fs.unlink(file, function (err) {
if(err) throw err;
console.log(file + '删除成功')
});
值得一提的是, 我上面的所有文件操作的地址,都是使用的绝对地址,用 __dirname + {文件当前地址} 获得绝对地址,这样做的初衷是担心放到服务器上会有问题
上面的代码我都单独跑过,没有问题,具体的代码实现细节我没有给出来,希望能大家参考这个思路,把里面的关键功能点都实现,然后串起来,做出自己的东西。
欢迎留言~