程序员

nodejs 爬虫 - 电子书应用与一键自动推送到 Kindl

2018-07-17  本文已影响0人  小丶王子

由于闲暇时间会看电子书小说,一时心血来潮,想搞个电子书爬虫,于是阅读了下 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 + {文件当前地址} 获得绝对地址,这样做的初衷是担心放到服务器上会有问题


上面的代码我都单独跑过,没有问题,具体的代码实现细节我没有给出来,希望能大家参考这个思路,把里面的关键功能点都实现,然后串起来,做出自己的东西。

欢迎留言~

上一篇下一篇

猜你喜欢

热点阅读