iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >利用Node.js制作爬取大众点评的爬虫
  • 447
分享到

利用Node.js制作爬取大众点评的爬虫

爬虫大众点评 2022-06-04 17:06:38 447人浏览 薄情痞子
摘要

前言 node.js天生支持并发,但是对于习惯了顺序编程的人,一开始会对node.js不适应,比如,变量作用域是函数块式的(与C、Java不一样);for循环体({})内引用i的值实际上是循环结束之后的值,

前言

node.js天生支持并发,但是对于习惯了顺序编程的人,一开始会对node.js不适应,比如,变量作用域是函数块式的(与C、Java不一样);for循环体({})内引用i的值实际上是循环结束之后的值,因而引起各种undefined的问题;嵌套函数时,内层函数的变量并不能及时传导到外层(因为是异步)等等。

一、 API分析

大众点评开放了查询餐馆信息的api,这里给出了城市与cityid之间的对应关系,

链接:Http://m.api.dianping.com/searchshop.JSONionid=0&start=0&cateGoryid=10&sortid=0&cityid=110

以GET方式给出了餐馆的信息(JSON格式)。

首先解释下GET参数的含义:

1、start为步进数,表示分步获取信息的index,与nextStartIndex字段相对应;

2、cityid表示城市id,比如,合肥对应于110;

3、regionid表示区域id,每一个id代表含义在start=0时rangeNavs字段中有解释;

4、categoryid表示搜索商家的分类id,比如,美食对应的id为10,具体每一个id的含义参见在start=0时categoryNavs字段;

5、sortid表示商家结果的排序方式,比如,0对应智能排序,2对应评价最好,具体每一个id的含义参见在start=0时sortNavs字段。

在GET返回的JSON串中list字段为商家列表,id表示商家的id,作为商家的唯一标识。在返回的JSON串中是没有商家的口味、环境、服务的评分信息以及经纬度的;

因而我们还需要爬取两个商家页面:http://m.dianping.com/shop/<id>、http://m.dianping.com/shop/<id>/map。

通过以上分析,确定爬取策略如下(与dianping_crawler的思路相类似):

1、逐步爬取searchshop API的取商家基本信息列表;

2、通过爬取的所有商家的id,异步并发爬取评分信息、经纬度;

3、最后将三份数据通过id做聚合,输出成json文件。

二、爬虫实现

Node.js爬虫代码用到如下的第三方模块:

1、superagent,轻量级http请求库,模仿了浏览器登录;

2、cheerio,采用Jquery语法解析html元素,跟python的PyQuery相类似;

3、async,牛逼闪闪的异步流程控制库,Node.js的必学库。

导入依赖库:


var util = require("util"); var superagent = require("superagent"); var cheerio = require("cheerio"); var async = require("async"); var fs = require('fs');

声明全局变量,用于存放配置项及中间结果:


var cityOptions = { "cityId": 110, // 合肥 // 全部商区, 蜀山区, 庐阳区, 包河区, 政务区, 瑶海区, 高新区, 经开区, 滨湖新区, 其他地区, 肥西县 "regionIds": [0, 356, 355, 357, 8840, 354, 8839, 8841, 8843, 358, -922], "categoryId": 10, // 美食 "sortId": 2, // 人气最高 "threshHold": 5000 // 最多餐馆数 }; var idVisited = {}; // used to distinct shop var ratingDict = {}; // id -> ratings var posDict = {}; // id -> pos

判断一个id是否在前面出现过,若object没有该id,则为undefined(注意不是null):


function isVisited(id) { if (idVisited[id] != undefined) { return true; } else { idVisited[id] = true; return false; } }

采取回调函数的方式,实现顺序逐步地递归调用爬虫函数:


function DianpingSpider(regionId, start, callback) { console.log('crawling region=', regionId, ', start =', start); var searcHBase = 'http://m.api.dianping.com/searchshop.json?®ionid=%s&start=%s&categoryid=%s&sortid=%s&cityid=%s'; var url = util.fORMat(searchBase, regionId, start, cityOptions.categoryId, cityOptions.sortId, cityOptions.cityId); superagent.get(url) .end(function (err, res) { if (err) return console.err(err.stack); var restaurants = []; var data = JSON.parse(res.text); var shops = data['list']; shops.forEach(function (shop) { var restaurant = {}; if (!isVisited(shop['id'])) { restaurant.id = shop['id']; restaurant.name = shop['name']; restaurant.branchName = shop['branchName']; var regex = /(.*?)(d+)(.*)/g; if (shop['priceText'].match(regex)) { restaurant.price = parseInt(regex.exec(shop['priceText'])[2]); } else { restaurant.price = shop['priceText']; } restaurant.star = shop['shopPower'] / 10; restaurant.category = shop['categoryName']; restaurant.region = shop['regionName']; restaurants.push(restaurant); } }); var nextStart = data['nextStartIndex']; if (nextStart > start && nextStart < cityOptions.threshHold) { DianpingSpider(regionId, nextStart, function (err, restaurants2) { if (err) return callback(err); callback(null, restaurants.concat(restaurants2)) }); } else { callback(null, restaurants); } }); }

在调用爬虫函数时,采用async的mapLimit函数实现对并发的控制;采用async的until对并发的协同处理,保证三份数据结果的id一致性(不会因为并发完成时间不一致而丢数据):


DianpingSpider(0, 0, function (err, restaurants) { if (err) return console.err(err.stack); var concurrency = 0; var crawlMove = function (id, callback) { var delay = parseInt((Math.random() * 30000000) % 1000, 10); concurrency++; console.log('current concurrency:', concurrency, ', now crawling id=', id, ', costs(ms):', delay); parseShop(id); parseMap(id); setTimeout(function () { concurrency--; callback(null, id); }, delay); }; async.mapLimit(restaurants, 5, function (restaurant, callback) { crawlMove(restaurant.id, callback) }, function (err, ids) { console.log('crawled ids:', ids); var resultArray = []; async.until( function () { return restaurants.length === Object.keys(ratingDict).length && restaurants.length === Object.keys(posDict).length }, function (callback) { setTimeout(function () { callback(null) }, 1000) }, function (err) { restaurants.forEach(function (restaurant) { var rating = ratingDict[restaurant.id]; var pos = posDict[restaurant.id]; var result = Object.assign(restaurant, rating, pos); resultArray.push(result); }); writeAsJson(resultArray); } ); }); });

其中,parseShop与parseMap分别为解析商家详情页、商家地图页:


function parseShop(id) { var shopBase = 'http://m.dianping.com/shop/%s'; var shopUrl = util.format(shopBase, id); superagent.get(shopUrl) .end(function (err, res) { if (err) return console.err(err.stack); console.log('crawling shop:', shopUrl); var restaurant = {}; var $ = cheerio.load(res.text); var desc = $("div.shopInfoPagelet > div.desc > span"); restaurant.taste = desc.eq(0).text().split(":")[1]; restaurant.surrounding = desc.eq(1).text().split(":")[1]; restaurant.service = desc.eq(2).text().split(":")[1]; ratingDict[id] = restaurant; }); } function parseMap(id) { var mapBase = 'http://m.dianping.com/shop/%s/map'; var mapUrl = util.format(mapBase, id); superagent.get(mapUrl) .end(function (err, res) { if (err) return console.err(err.stack); console.log('crawling map:', mapUrl); var restaurant = {}; var $ = cheerio.load(res.text); var data = $("body > script").text(); var latRegex = /(.*lat:)(d+.d+)(.*)/; var lngRegex = /(.*lng:)(d+.d+)(.*)/; if(data.match(latRegex) && data.match(lngRegex)) { restaurant.latitude = latRegex.exec(data)[2]; restaurant.longitude = lngRegex.exec(data)[2]; }else { restaurant.latitude = ''; restaurant.longitude = ''; } posDict[id] = restaurant; }); }

将array的每一个商家信息,逐行写入到json文件中:


function writeAsJson(arr) { fs.writeFile( 'data.json', arr.map(function (data) { return JSON.stringify(data); }).join('n'), function (err) { if (err) return err.stack; }) }

总结

以上就是这篇文章的全部内容,希望本文能给学习或者使用node.js的朋友们带来一定的帮助,如果有疑问大家可以留言交流。

--结束END--

本文标题: 利用Node.js制作爬取大众点评的爬虫

本文链接: https://www.lsjlt.com/news/12960.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 利用Python网络爬虫爬取各大音乐评论的代码
    目录 python爬虫--爬取网易云音乐评论1.简易看出评论是动态加载的,一定是ajax方式。3.去查看post请求所上传的数据4.首先去查看请求是经过那些js到达服务器的...
    99+
    2024-04-02
  • 如何利用aiohttp制作异步爬虫
    这篇文章主要介绍“如何利用aiohttp制作异步爬虫”,在日常操作中,相信很多人在如何利用aiohttp制作异步爬虫问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何利用aiohttp制作异步爬虫”的疑惑有所...
    99+
    2023-06-17
  • 怎么用python爬虫获取豆瓣的书评
    小编给大家分享一下怎么用python爬虫获取豆瓣的书评,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!python的五大特点是什么python的五大特点:1.简单易...
    99+
    2023-06-14
  • python爬虫怎么利用requests制作代理池s
    本篇内容介绍了“python爬虫怎么利用requests制作代理池s”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  爬取代理然后验证代理,...
    99+
    2023-06-02
  • 利用Python爬虫爬取金融期货数据的案例分析
    目录任务简介解决步骤代码实现总结大家好 我是政胤今天教大家爬取金融期货数据 任务简介 首先,客户原需求是获取https://hq.smm.cn/copper网站上的价格数据(注:获取...
    99+
    2024-04-02
  • 如何利用Node.js做简单的图片爬取
    目录介绍安装引入创建实例元素捕获下载图片结语介绍 爬虫的主要目的是收集互联网上公开的一些特定数据。利用这些数据我们可以能进行分析一些趋势对比,或者训练模型做深度学习等等。本期我们就将...
    99+
    2024-04-02
  • 【Python】爬虫练习-爬取豆瓣网电影评论用户的观影习惯数据
    目录 前言 一、配置环境 1.1、 安装Python 1.2、 安装Requests库和BeautifulSoup库 1.3.、安装Matplotlib 二、登录豆瓣网(重点) 2.1、获取代理 2.2、测试代理ip是否可用 2.3、设置...
    99+
    2023-10-25
    windows python 开发语言 爬虫
  • Golang多线程爬虫高效抓取大量数据的利器
    目录前言goroutine(Go 协程)channel(通道)channel 的初始化channel的关闭waitGroup 的使用爬虫爬虫配置爬虫数据开启并行爬取某个链接爬取某个链...
    99+
    2023-05-19
    Golang多线程爬虫 Golang爬虫 Golang多线程
  • 使用JavaIO流和网络制作一个简单的图片爬虫
    目录Java IO流和网络的简单应用Java IO 流和 URL 类Java IO流URL 类Java 爬虫ClientDataProcessUtilDownLoadUtilWind...
    99+
    2023-05-14
    JavaIO流 网络 JavaIO流爬虫 图片爬虫
  • 如何使用Python3制作一个带GUI界面的小说爬虫工具
    这篇文章主要介绍如何使用Python3制作一个带GUI界面的小说爬虫工具,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!效果图最近帮朋友写个简单爬虫,顺便整理了下,搞成了一个带GUI界面的小说爬虫工具,用来从笔趣阁爬取...
    99+
    2023-06-29
  • 用Python爬取暑期档大火的《哪吒》,20W+评论数据,我们分析一波
    说起这个暑期档的动画片,非《哪吒之魔童降世》莫属了!上映第 1 天:89分钟,中国动画最快破 1亿纪录上映第 2 天:中国影史首部单日票房破 2亿的动画电影上映第 4 天:中国影史第66部破 10亿影片上映第 8 天:正式登顶!破 16亿,...
    99+
    2023-06-02
  • 怎么使用Java IO流和网络制作一个简单的图片爬虫
    这篇文章主要介绍“怎么使用Java IO流和网络制作一个简单的图片爬虫”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用Java IO流和网络制作一个简单的图片爬虫”文章能帮助大家解决问题。Ja...
    99+
    2023-07-05
  • 使用python爬取吉首大学网站成绩单的操作介绍
    本篇文章和大家了解一下使用python爬取吉首大学网站成绩单的操作介绍。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。项目地址:https://github.com/chen0495/pythonCrawlerForJSU...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作