diff --git "a/source/_posts/\344\270\200\344\270\252\347\256\200\345\215\225\347\232\204node\347\210\254\350\231\253\345\256\236\347\216\260.md" "b/source/_posts/\344\270\200\344\270\252\347\256\200\345\215\225\347\232\204node\347\210\254\350\231\253\345\256\236\347\216\260.md" new file mode 100644 index 0000000..209e3f4 --- /dev/null +++ "b/source/_posts/\344\270\200\344\270\252\347\256\200\345\215\225\347\232\204node\347\210\254\350\231\253\345\256\236\347\216\260.md" @@ -0,0 +1,98 @@ + + +### 前言 +之前有接触到一些做node爬虫的工程师,在获取淘宝卖家授权后,通过nodejs爬取该卖家的淘宝店各项信息,获得每月销售额、好评率等各项信息,对此较感兴趣,自己实现了一个简单的爬虫,爬取计量一新闻库,将文章内容、图片保存至本地。 + +### 实现方式 +实现这样的效果其实很简单,通过request模块请求某一个新闻页的html,然后通过cheerio实现类似于JQuery操作dom的效果,将你所需要的信息从dom中获取出来。 + +### 主要实现步骤 +1. 通过分析http://www.cjlu.edu.cn/do.jsp?dotype=newsmm&columnsid=13¤tPage=1 该新闻库可以发现,该类目下新闻共有64页,每页30条新闻,url参数currentPage对应分页页码。 +2. 使用request发送get请求,获取第一分页的html,然后用cheerio分析html,获取当前页内每一条新闻的链接,存入数组urlList。通过network可以发现,该http请求Response Header内Transfer-Encoding: chunked,代表服务端是一边产生数据,一边发给客户端,所以监听data事件,将获取到的data拼接成完整的html。 + +``` +let html = ''; +request + .get(url) //http://www.cjlu.edu.cn/do.jsp?dotype=newsmm&columnsid=13¤tPage=1 + .on('data',chunk =>{ + html += chunk; + }) + .on('end',() =>{ + let $ = cheerio.load(html); + let urlList = []; + let length = $('.new-main-list li').length; + $('.new-main-list li').each((index) =>{ + let link = 'http://www.cjlu.edu.cn'+$('.new-main-list li a').eq(index).attr('href'); + urlList.push(link); + }) + resolve(urlList); + }) +``` + +3. 然后依次通过request请求每一条新闻,获取其中的新闻内容和图片,新闻内容使用fs.createWriteStream在本地创建txt文件,并使用fs.appendFileSync写入,图片下载保存到本地。 + +``` +//将新闻文本内容一段一段添加到/data文件夹下,并用新闻的标题来命名文件 +let fileName = `data/${i}_${news_title}.txt`; +fs.createWriteStream(fileName); +$('.main_box').next().find('p').each(function (index, item) { + let x = $(this).text(); + if (x != '') { + x = x + '\n'; + fs.appendFileSync(fileName, x, { encoding: 'utf8'}); + } +}) +``` + +``` +//将新闻内使用图片下载到本地 +request + .get(url) + .on('error', err => { + error_url.push(url); + }) + .pipe(fs.createWriteStream('image/'+img_title)); +``` + +4. 期间使用async.mapLimit限制并发请求的数量,防止服务器封IP,当然这样的方式是比较简陋的,可以使用动态IP的方式请求。 + +``` +async.mapLimit(urlLists, 5, function (url, callback) { + fetchPage(url, callback); +}, function (err,result) { + console.log('final:'); + console.log(error_url); + console.log(result) +}); +``` + +### Nightmare介绍 +nightmare号称爬虫的终极形态,它是一个基于electron的自动化库(自带浏览器),常用于实现爬虫或自动化测试。
+#### 那么它能实现什么功能? +它可以通过获取dom的方式,模拟用户的操作,比如点击链接、输入账号密码自动登录等,可以通过wait底部元素得到页面dom加载完毕的事件。

+ +在爬豆瓣电影排行榜时,担心被反爬虫机制封IP,就使用了nightmare模拟用户操作,查看排行榜,点击翻页等操作。 + +``` +nightmare + .goto('https://movie.douban.com/') + .click('#db-nav-movie > div.nav-secondary > div > ul > li:nth-child(4) > a') + .click('.douban-top250-hd a') + .wait('#footer') + .evaluate(function () { + let i = 1; + let urlList = []; + while(i<26){ + urlList.push(document.querySelector('#content > div > div.article > ol > li:nth-child('+i+') > div > div.info > div.hd > a').getAttribute('href')) + i++; + } + return urlList; + }) +``` +