本文继续上一章内容
现在我们只是实现了下载固定页面的所有子页面的图片, 功能还很粗糙, 比如:
1: 页面啥都看不到, 总共有多少页面, 多少图片我都不清楚, 下载进度如何了?
2: 来回就下载一个页面, 如果能动态点就好了, 比如搜什么, 下载什么.
好, 我们就脑补下接下来怎么办?
第一条, 我们可以使用 websocket 相关技术, 让浏览器和服务器通信, 让相关信息显示在浏览器上, 这样用户体验会好点.
第二条, 我们可以通过输入点什么, 传到后端, 然后让它根据我输入的关键词爬取.
关键技术点:
https://socket.io/
这个是 node 的一个工具包, 就是解决浏览器和 服务器之间 实时通信的问题. 用这个工具我们可以解决显示进度问题
写法很简单, 首先, 服务器和 浏览器初始化, 然后绑定或者触发事件, 服务器和浏览器都可以 socket.on 和 socket.emit 事件.
类似这样:
- // 服务器:
- let io = require('socket.io')(server);
- io.on('connection', (client) => {
- client.on('start',msg =>{
- console.log('start');
- socket.init(io , msg);
- });
- //client.emit('progress', data)
- });
- // 客户端
- script(src="/javascripts/socket.io-client/dist/socket.io.js")
- script.
- var socket = io();
- socket.on('progress', function (data) {
- if(data.type == 'detail'){
- }else if(data.type == 'page'){
- $('#msg .page').text(` 总共有 ${data.msg} 个页面 `)
- }else if(data.type == 'img'){
- $('#msg .img').text(` 总共有 ${data.msg} 个图片 `)
- }
- switch (data.type) {
- case 'detail':
- let li = `<li>${data.msg}</li>`;
- $('#msg ul').append(li);
- break;
- case 'page':
- $('#msg .page').text(` 总共有 ${data.msg} 个页面 `)
- break;
- case 'img':
- $('#msg .img').text(` 总共有 ${data.total} 个图片, 已下载:${data.num}`)
- break;
- case 'err':
- alert(data.msg);
- break;
- case 'done':
- $('#done').show();
- break;
- }
- })
- $('#tian').click(function (evt) {
- var keywords = $('#keywords').val();
- socket.emit('start', keywords);
- })
服务器的大致处理脚本:
- init(io, msg){
- const reptileUrl = "http://www.meisiguan.cc/?s=";
- this.IO = io;
- //this.IO.on('disconnect')
- if(!msg){
- this.sendClient({
- type: 'err',
- msg: '请输入关键词'
- })
- }else{
- superagent.get(reptileUrl + msg).end((err, res) =>{
- // 抛错拦截
- if (err) {
- throw Error(err);
- return;
- }
- let $ = cheerio.load(res.text);
- let data = [];
- // 下面就是和 jQuery 一样获取元素, 遍历, 组装我们需要数据, 添加到数组里面
- $('#index_ajax_list li').each(function (i, elem) {
- let _this = $(elem);
- data.push({
- img: _this.find('img').attr('src'),
- title: _this.find('img').attr('alt'),
- href: _this.find('a').attr('href')
- });
- });
- this.pageNum = data.length;
- this.sendClient({
- type: 'page',
- msg: this.pageNum
- })
- this.getSonPage(data);
- });
- }
- },
然后看到的效果基本上是这样:
改进的地方:
1: 业务逻辑改了, 原先是直接请求首页就直接下载, 现在改成输入关键词, 点击按钮开始执行.
2: 文件结构, 原先直接写到 router.js 里, 其实很不合理, 现在把通信和下载的核心代码抽取出来, 放到 bin/mods 里面.
3: 下载文件名, 用了目标网站的部分图片名称, 这样下载不同的关键词图片, 不会覆盖掉, 可以保存更多的图片
讲的不够细致, 貌似耐心不够好, 抱歉了.
老规矩, 放上源码:
https://github.com/tianxiaofeng747/nodeImg
现在的问题:
1: 假如遇到某些子页面是死链接, node 就会报错退出, 这其实不友好
2: 没有判断同样的关键词不能爬取第二遍
3: 正在爬取的时候应该禁用掉浏览器 开始 按钮
4: 下载完后是否可以提供一个页面直接去浏览查看所有的图片?
就先这样把. 吃饭, 吃饭.
来源: http://www.qdfuns.com/article/14245/9ac72ceb44604bc943691609b5b24edb.html