Node.js可能是最适合写简易小爬虫的语言,速度极快(以爬取豆瓣top250为例)
“凡是能用JS 写出来的,最终都会用JS 写”,这是一个非常著名的定律,用在爬虫这里再合适不过了。
一说到爬虫很多人都会想到python,的确,python语法简洁,还有scrapy这一类强大的工具可以使用。
但是如果只是想写一个小爬虫,爬取论坛里的几张帖子,帖子里面的几个楼层,然后合成一篇文章。这点小数据量使用scrapy就有点杀鸡用牛刀了,而且还得设置一堆东西,非常麻烦,不够灵活。
而JavaScript就非常适合这一类小爬虫,首先是自带异步架构,能同时爬取多张网页内容,效率上来说比python高多了,我用两个语言写过爬取代理ip的爬虫,当JavaScript爬完时吓了我一跳,这速度快极了。
当然,python也可以通过开启多线程、多协程来实现同时爬取多张网页,但是这就比默认就异步的JavaScript麻烦多了。
所以,如果想简单、高效地写个小爬虫,非JavaScript莫属。
有多快多简单呢?现在就来写个豆瓣top250的爬虫,爬取10张网页,250部电影的名字、评分和封面地址;
1.如何安装
要通过js写爬虫,需要用到三个模块,request、cheerio和fs,其中fs内置了,只需要安装前两个即可,安装命令:
npm install request cheerio
2.获取网页内容
request可以链接网页,爬取内容,这里我们只需要给它传递两个参数就行,一个为url(网址),另一个为回调函数;
request会向回调函数传递三个参数,分别是error(错误信息),response(响应信息),body(网页内容):
var request = require('request') var cheerio = require('cheerio') var fs = require('fs') var movies = [] var requstMovie = function(url){ request('https://movie.douban.com/top250',function(error, response, body)){ //res.statusCode 为200则表示链接成功 if(error === null && response.statusCode === 200){ console.log('链接成功') //使用cheerio来解析body(网页内容),提取我们想要的信息 var e = cheerio.load(body) //通过分析网页结构,我们发现豆瓣每部电影都通过item属性隔开 var movieDiv = e('.item') //通过for循环来提取每部电影里的信息 for (let i = 0; i < movieDiv.length; i++) { //takeMovie函数能提取电影名称、评分和封面 let movieInfo = takeMovie(movieDiv[i]) log('正在爬取' + movieInfo.name) //将提取到的电影放入数组 movies.push(movieInfo) } } }) }
3.提取电影信息
通过创建一个类来包含我们想要的属性,在每次调用takeMovie函数提取信息时都会初始化这个类,然后赋值给相应的属性;
之后放入movies数组里;
//电影的类 var movie = function(){ this.id = 0 this.name = '' this.score = 0 this.pic = '' } var takeMovie = function(div){ var e = cheerio.load(div) //将类初始化 var m = new movie() m.name = e('.title').text() m.score = e('.rating_num').text() var pic = e('.pic') //cheerio如果要提取某个属性的内容,可以通过attr() m.pic = pic.find('img').attr('src') m.id = pic.find('em').text() return m }
4.爬取所有top250
现在要爬取所有的top250信息,总共有10张网页,每张包含25部电影信息,创建一个函数来生成每张网页的网址,然后通过request进行爬取:
var top250Url = function(){ let l = ['https://movie.douban.com/top250'] var urlContinue = 'https://movie.douban.com/top250?start=' let cont = 25 for (let i = 0; i < 10; i++) { l.push(urlContinue+cont) cont += 25 } return l } //爬取所有网页 var __main = function(){ var url = top250Url() for (let i = 0; i < url.length; i++) { requstMovie(url[i]) } } __main()
5.异步架构的坑
当我们爬取完所有的网页后就会发现,movies里的电影信息并不按我们爬取的顺序,这也是异步架构一个需要注意的大坑;
在爬取第一张网页时,JavaScript不会等到处理结束才接着爬第二张,有时候各个网页返回的速度有所差异,会造成先爬取的不一定会先出结果,因此在电影排序上会出现混乱;
所以我们还需要对爬取下来的内容重新进行排序,然后保存:
//sortMovie回调函数能比较两个对象属性大小 var sortMovie = function(id){ return function(obj ,obj1){ var value = obj[id] var value1 = obj1[id] return value - value1 } } //保存文件 var saveMovie = function(movies){ var path = 'movie.txt' var data = JSON.stringify(movies, null, 2) fs.appendFile(path, data, function(error){ if(error == null){ log('保存成功!') } else { log('保存失败',error) } }) }
我们需要等到所有网页都爬取分析完才执行sortMovie和saveMovie函数,由于JavaScript是异步,即使这两个函数放在最底部也会在分析完之前执行;
一般会通过Promise来控制异步,但是为了方便,这里我们通过if来判断,在每次爬取网页后,都会判断movies里是否包含250条信息,如果有则说明全部爬取到了:
var requstMovie = function(url){ request(url, function(error, response, body){ if (error === null && response.statusCode === 200){ var e = cheerio.load(body) var movieDiv = e('.item') for (let i = 0; i < movieDiv.length; i++) { let movieInfo = takeMovie(movieDiv[i]) log('正在爬取' + movieInfo.name) movies.push(movieInfo) } //判断movies数量 if (movies.length === 250){ //通过sort将数组内每两个元素放入比较函数 var sortM = movies.sort(sortMovie('id')) //保存文件 saveMovie(sortM) } } else { log('爬取失败', error) } }) }
到这里,爬虫已经写完了,来运行一下:
完整代码可以通过github查看:DoubanMovies.JS
也可以访问我的网站,获取更多文章:Nothlu.com
- Node.js的简易爬虫
- Node.js 实现简易爬虫
- PHP, Python, Node.js 哪个比较适合写爬虫?
- [js高手之路]Node.js实现简易的爬虫-抓取博客所有文章列表信息
- node.js做的一个简单爬虫,适合菜鸟级新手,针对无防爬措施的网站
- 使用node.js制作简易爬虫
- [js高手之路]Node.js实现简易的爬虫-抓取博客所有文章列表信息
- 从零学习node.js之简易的网络爬虫(四)
- Node.js 网页瘸腿稍强点爬虫再体验
- Node.js 网页爬虫再进阶,cheerio助力
- 转载:js动态获取图片长宽尺寸(兼容所有浏览器,速度极快)
- 一起学爬虫 Node.js 爬虫篇(一)
- [js高手之路]Node.js+jade+mongodb+mongoose实现爬虫分离入库与生成静态文件
- 手把手教你多页面递归爬虫--基于Node.Js
- 关于Node.js中Buffer的一些你可能不知道的用法
- Python爬虫之多线程下载豆瓣Top250电影图片
- node.js 小爬虫
- 10 个优化技巧加快你的 Node.js 应用运行速度
- node.js爬虫爬取拉勾网职位信息
- node.js适合游戏后台开发吗?