摘要:前言很多程序猿在最开始学习开发的时候应该都有一个想要自己开发一个爬虫的想法至少我是有的。其实弄懂了爬虫的原理,再回过头去看,发现开发一个简单的爬虫来说还是很容易的。
前言
很多程序猿在最开始学习开发的时候应该都有一个想要自己开发一个爬虫的想法(至少我是有的)。所以国内网络上也是爬虫盛行!学了node.js之后发现比较适合写爬虫,不过一直没有动手去写,正好这段时间比较闲,就写个爬虫玩下。
想着爬个什么东西呢?正好都比较喜欢看电影,那就从时光网爬下国内的票房排行榜吧。
Talk is cheap. Show me the code不bb,代码在此
如何"食用"git clone https://github.com/XNAL/node-MovieSpider cd node-MovieSpider npm init node index.js搭建环境
开发语言:node.js
发出http请求:superagent
并发控制:async
分析网页内容:cheerio
开始撸代码 1. 代码主体作为一个简单的示例,此次就不开启node服务了,我这里就直接来个自执行的方法。如果有需要,可以根据自己的需求扩展。
// 启动时直接执行代码
(function spider() {
util.fetch_data_get(reqUrl, reqParams)
.then((result) => {
// 根据页面结构获取总的页数,然后再分页获取数据
let $ = cheerio.load(result.body.html);
let pageTotal = $(".bocontent .pagesize a:last-child").data("page") || 0;
console.log("电影数据总页数:", pageTotal);
return pageTotal;
})
.then((pageTotal) => {
// 分页获取数据
getMovieData(0, pageTotal);
})
.catch((err) => {
console.log("获取链接失败:", err);
})
})();
2. 发送请求
因为代码中需要多次发送http请求,所以把http请求写成一个公共方法会比较好。使用上面提到superagent库来实现。
// 公共方法:通过get请求获取数据
function fetch_data_get(url, queryParams) {
return new Promise((reslove, reject) => {
superagent
.get(url)
.set(setting.header)
.query(queryParams)
.end((err, result) => {
err ? reject(err) : reslove(result);
})
})
}
3. 分析目标网站api
根据人工操作得来的apihttp://movie.mtime.com/boxoffice/?year=2017&area=china&type=MovieRankingYear&category=all&page=0&display=list×tamp=1505818638620&version=07bb781100018dd58eafc3b35d42686804c6df8d&dataType=json可以得到以下参数:
// 根据网站api得到相应的url和参数
const reqUrl = "http://movie.mtime.com/boxoffice/";
const reqParams = {
"year": 2017,
"area": "china",
"type": "MovieRankingYear",
"category": "all",
"page": 0,
"display": "list",
"timestamp": 1501576013654,
"version": "07bb781100018dd58eafc3b35d42686804c6df8d",
"dataType": "json"
};
因为此次要获取的是2017年内地票房排行榜。根据分析可知:需要变动的主要是page参数,那这里就需要根据页面返回的内容来取得总的page。
4. 使用cheerio获取所需参数api返回的页面内容可查看:将api获取的数据格式化后的页面代码。
这里需要用到cheerio来取页码总数的代码,cheerio可以理解为服务器端的jQuery,用法也类似:
// 根据页面结构获取总的页数,然后再分页获取数据
let $ = cheerio.load(result.body.html);
let pageTotal = $(".bocontent .pagesize a:last-child").data("page") || 0;
5. 开始分页取目标数据
<1> 调用上面所说的公共方法fetch_data_get获取数据,然后取页面内容,图片地址都先保存在movieImgs中,最后再统一下载图片:
// 根据页面结构获取所需数据
let $ = cheerio.load(result.body.html);
$(".bocontent .boxofficelist dd").each((idx, elem) => {
$(elem).find("div.movietopmod").each((i, el) => {
let _this = $(el);
let arrLeadActor = [];
_this.find(".txtbox b p").eq(1).find("a").each((idx, ela) => {
arrLeadActor.push($(ela).text());
})
movieData.push({
rank: _this.find(".picbox i").text(),
img: _this.find(".picbox img").attr("src").replace(//u//, ""),
name: _this.find(".txtbox h3").text(),
director: _this.find(".txtbox b p").eq(0).find("a").text(),
leadActor: arrLeadActor.join(","),
point: _this.find(".gradebox .point").text(),
total: _this.find(".totalbox .totalnum").text()
}),
movieImgs.push(_this.find(".picbox img").attr("src").replace(//u//, ""));
})
})
<2> 根据页码循环取数据
if(pageIndex <= pageTotal) {
// 设置timeout防止网站反爬虫
setTimeout(() => {
pageIndex ++;
getMovieData(pageIndex, pageTotal);
}, setting.timeout);
}
<3> 全部数据取出后存储数据,并下载图片。
因为只是一个简单的示例,所以此次数据只是保存到json文件中。如果需要对数据进行后续操作的话,那就最好保存到数据库中:
fs.writeFile(dataDir + reqParams.year + ".json", JSON.stringify(movieData), (err) => {
if (err) {
console.log(err);
} else {
console.log("数据写入成功");
}
});
调用下载图片的方法:
let folderName = imgPrefix + reqParams.year; util.downloadImg(movieImgs, folderName);
util.js中的downloadImg方法:这里就需要用到上面所说的async,使用async是为了进行并发控制,不然极短时间发送至少几十几百次的请求,这种情况弄不好就被网站的发爬虫程序给封了,而且大量并发也会导致出错的概率更高。
// 异步下载图片
function downloadImg(urls, folderName) {
async.mapLimit(urls, setting.asyncNum, (img, callback) => {
fetch_data_get(img, {})
.then((result) => {
let fileName = path.basename(img);
let folder = imgDir + folderName;
if(!fs.existsSync(folder)) {
fs.mkdirSync(folder);
}
fs.writeFile(folder + "/" + fileName, result.body, (err) => {
if (err) {
console.log(img, "图片写入失败:", err);
} else {
console.log(img, "图片写入成功");
callback(null , fileName);
}
})
})
.catch((err) => console.log(err))
}, (err, result) => {
if (err) {
console.log("图片下载失败:", err)
} else {
console.log(result);
}
})
}
结语
到此为止一个简单的node.js版的小爬虫就开发完成了。其实弄懂了爬虫的原理,再回过头去看,发现开发一个简单的爬虫来说还是很容易的。
最后,欢迎大家去我的github进行star和fork。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/91965.html
摘要:爬虫介绍二爬虫的分类通用网络爬虫全网爬虫爬行对象从一些种子扩充到整个,主要为门户站点搜索引擎和大型服务提供商采集数据。 分分钟教你用node.js写个爬虫 写在前面 十分感谢大家的点赞和关注。其实,这是我第一次在segmentfault上写文章。因为我也是前段时间偶然之间才开始了解和学习爬虫,而且学习node的时间也不是很长。虽然用node做过一些后端的项目,但其实在node和爬虫方面...
摘要:一个爬虫租房软件。获取导航页以及数据打开同城主页,我主要针对杭州的二手房进行了爬取分析,所以进入杭州租房。这次我们需要解析房屋所在地信息,用来可视化显示。具体做法可以参照相关反爬虫策略的文章。 一个爬虫租房软件。 先上一个源代码吧。 https://github.com/answershuto/Rental 欢迎指导交流。 效果图 showImg(https://segmentfau...
摘要:今天开源了一个百度云网盘爬虫项目,地址是。推荐使用命令安装依赖,最简单的安装方式更多安装的命令可以去上面找。启动项目使用进行进程管理,运行启动所有的后台任务,检查任务是否正常运行可以用命令,正常运行的应该有个任务。 今天开源了一个百度云网盘爬虫项目,地址是https://github.com/callmelanmao/yunshare。 百度云分享爬虫项目 github上有好几个这样的...
摘要:这里由于京东的分界面都使用了,所以我们可以用,总之他们开发能用的选择器,我们都可以用,否则就不可以。 难道爬虫只能用 python 做? 不,我们上天的 Node.js 也可以做! 需要准备的包 Node.js的最新版本 下载地址 Node.js官网 npm 包管理器下载 下载最新的官网版本 Node.js 会自带 npm npm的第三方包 puppeteer 在对应...
摘要:这里由于京东的分界面都使用了,所以我们可以用,总之他们开发能用的选择器,我们都可以用,否则就不可以。 难道爬虫只能用 python 做? 不,我们上天的 Node.js 也可以做! 需要准备的包 Node.js的最新版本 下载地址 Node.js官网 npm 包管理器下载 下载最新的官网版本 Node.js 会自带 npm npm的第三方包 puppeteer 在对应...
阅读 2030·2021-11-25 09:43
阅读 2014·2021-11-24 10:41
阅读 3492·2021-09-27 13:36
阅读 977·2019-08-30 15:53
阅读 3836·2019-08-30 15:44
阅读 1077·2019-08-30 14:03
阅读 2798·2019-08-29 16:38
阅读 1228·2019-08-29 13:23