最近在做一个书城项目,数据用爬虫爬取,百度了一下找到这个网站,以择天记这本小说为例。

爬虫用到了几个模块,cheerio,superagent,async。

superagent是一个http请求模块,详情可参考链接。

cheerio是一个有着jQuery类似语法的文档解析模块,你可以简单理解为nodejs中的jQuery。

async是一个异步流程控制模块,在这里我们主要用到async的mapLimit(coll, limit, iteratee, callback)

async.mapLimit(urls, 10, function (url, callback) {fetchUrl(url, callback, id)}, function (err, results) {//TODO})

第一个参数coll是一个数组,保存了小说的章节url,第二个参数limit是控制并发数,第三个参数iteratee接受一个回调函数,该回调函数的第一个参数就是单独某一章的url,第二个参数也是一个回调函数,这个回调函数执行后会把结果(在这里就是每一章的内容)保存到第四个参数callback的results中,results是一个数组,保存了所有章节的内容。

我们在fetchUrl获取章节数据。

首先我们要根据小说的主页url获取所有章节的url保存到数组urls中:

superagent.get(url).charset('gbk')  //该网站编码为gbk,用到了superagent-charset.end(function (err, res) {var $ = cheerio.load(res.text); //res.text为获取的网页内容,通过cheerio的load方法处理后,之后就是jQuery的语法了let urls = []total = $('#list dd').lengthconsole.log(`共${$('#list dd').length}章`)$('#list dd').each(function (i, v) {if (i < chapters) {urls.push('http://www.zwdu.com' + $(v).find('a').attr('href'))}})

fetchUrl函数

function fetchUrl(url, callback, id) {superagent.get(url).charset('gbk').end(function (err, res) {let $ = cheerio.load(res.text)//obj为构建的包含章节信息的对象callback(null, obj)  //将obj传递给第四个参数中的results
    })
}

完整代码:

/*** Created by tgxh on 2017/7/4.*/
const cheerio = require('cheerio')
const express = require('express')
const app = express()
const superagent = require('superagent')
require('superagent-charset')(superagent)
const async = require('async');let total = 0 //总章节数
let id = 0 //计数器
const chapters = 10 //爬取多少章
const url = 'http://www.zwdu.com/book/8634/'//去除前后空格和&nbsp;转义字符
function trim(str) {return str.replace(/(^\s*)|(\s*$)/g, '').replace(/&nbsp;/g, '')
}//将Unicode转汉字
function reconvert(str) {str = str.replace(/(&#x)(\w{1,4});/gi, function ($0) {return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{1,4})(%3B)/g, "$2"), 16));});return str
}function fetchUrl(url, callback, id) {superagent.get(url).charset('gbk').end(function (err, res) {let $ = cheerio.load(res.text)const arr = []const content = reconvert($("#content").html())//分析结构后分割htmlconst contentArr = content.split('<br><br>')contentArr.forEach(elem => {const data = trim(elem.toString())arr.push(data)})const obj = {id: id,err: 0,bookName: $('.footer_cont a').text(),title: $('.bookname h1').text(),content: arr.join('-')  //由于需要保存至mysql中,不支持直接保存数组,所以将数组拼接成字符串,取出时再分割字符串即可}callback(null, obj)  })
}app.get('/', function (req, response, next) {superagent.get(url).charset('gbk').end(function (err, res) {var $ = cheerio.load(res.text);let urls = []total = $('#list dd').lengthconsole.log(`共${$('#list dd').length}章`)$('#list dd').each(function (i, v) {if (i < chapters) {urls.push('http://www.zwdu.com' + $(v).find('a').attr('href'))}})async.mapLimit(urls, 10, function (url, callback) {id++fetchUrl(url, callback, id) //需要对章节编号,所以通过变量id来计数}, function (err, results) {response.send(results)})})
})app.listen(3378, function () {console.log('server listening on 3378')
})

结果如下:

转载于:https://www.cnblogs.com/tgxh/p/7124202.html

【nodejs爬虫】使用async控制并发写一个小说爬虫相关推荐

  1. 用python写一个简单的爬虫_用Python从零开始写一个简单爬虫

    import requests from bs4 import BeautifulSoup url = "https://tieba.baidu.com/f?kw=王者荣耀&fr=h ...

  2. Node爬虫之使用 async 控制并发

    上文 <Node爬虫之使用 eventproxy 控制并发>我们说到用 node 爬了csdn首页数据,但是这些请求完全是并发的,如果某些网站有 "反爬" 机制,就很有 ...

  3. 从0开始写一个多线程爬虫(2)

    上一篇文章: 从0开始写一个多线程爬虫(1) 我们用继承Thread类的方式来改造多线程爬虫,其实主要就是把上一篇文章的代码写到线程类的run方法中,代码如下: import re import re ...

  4. python爬虫都能干什么用_5 行代码就能写一个 Python 爬虫

    欢迎关注我的公众号:第2大脑,或者博客:高级农民工,阅读体验更好. 摘要:5 行代码就能写一个 Python 爬虫. 如果你是比较早关注我的话,会发现我此前的大部分文章都是在写 Python 爬虫,前 ...

  5. 用c语言写一个网络爬虫

    (同步个人博客 http://sxysxy.org/blogs/28 到csdn 写一个网络爬虫 写一个网络爬虫,来获取一个网站上感兴趣的信息. 最基本的模型 就是图.每个页面看作一个节点,若页面A有 ...

  6. 用爬虫写一个,小说下载程序

    用爬虫写一个,小说下载程序 环境:python 3.7.3 没啥难度和技术含量,随便写写.本来程序有部分可用format进行优化,但又想了想小说名可能还会 有一些奇奇怪怪的符号,就没弄了. impor ...

  7. 【直播】手把手带你 5 分钟写一个小爬虫,从入门到超神!

    在程序员界流传着这么一个顺口溜:爬虫玩得好,监狱进得早.数据玩得溜,牢饭吃个够--时不时还有 "XX 公司做违法爬虫,程序员坐牢" 的新闻爆出. 在看热闹的同时,很多人都会提出疑问 ...

  8. 用Python写一个网络爬虫爬取网页中的图片

    写一个爬虫爬取百度贴吧中一个帖子图片 网址:壁纸 用谷歌浏览器的开发工具检查网页,可以发现其每一张图片都有如下格式 <img class="BDE_Image" src=&q ...

  9. 五分钟写一个小爬虫,爬取小说并写入txt文件

    先上代码: #-*- coding:UTF-8 -*- import requests from lxml import html url='http://www.shuge.net/html/111 ...

最新文章

  1. python代码通过日期获得星期信息(根据日期获取星期day of the week)
  2. linux查找日期目录,详解Linux查找目录下的按时间过滤的文件
  3. 快速创建包快捷键大全_99个CAD插件大全,各种工具箱和超实用辅助插件,绘图从此不卡顿...
  4. 无法嵌入互操作类型 请改用适用的接口_机器视觉可用的不同电缆和连接器类型以及相关利弊分析...
  5. 利用计算机程序解决问题的基本过程,第四章第一节编制计算机程序解决问题
  6. esper_Twitter4j和Esper:在Twitter上跟踪用户情绪
  7. 网管交换机怎么设置?网管交换机设置方法
  8. python3所支持的整数进制_Python3快速入门(三)——Python3标准数据类型
  9. 秒懂文件路径 / 和 ./ 和 ../ 和 ../../
  10. 操作系统重装或还原后Domino 8 无法启动解决方法
  11. 如何修改bt tracker服务器,bt tracker服务器
  12. P1589 - 【NOI2009】植物大战僵尸
  13. css模拟title和alt的提示效果[转]
  14. Echart地图的省级,以及所有地市级下载与使用
  15. MySQL数据分析-(12)表操作补充:字段属性
  16. [已解决]Notepad++ 无法安装HexEditor
  17. JdbcTemplate数据库连接耗尽问题排查
  18. [UVa 1646] Edge Case
  19. 关于背单词的一点个人体会 (好文章)
  20. python生成随机的测验试卷_python生成随机的测验试卷文件

热门文章

  1. Django静态文件配置
  2. 在树莓派上用python控制LED
  3. mysql创建表对经常要查询的列添加索引或者组合索引
  4. 入手你从来没有接触过的行业项目
  5. linux命令scp
  6. 十六进制字符转二进制字符
  7. 《java多线程编程实战指南 核心篇》读书笔记一
  8. springmvc十一: @RequestMapping-ant风格的url
  9. CentOS7援救模式下更改密码
  10. laravel 的 表单请求