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

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


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

欢迎留言~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容