[Nodejs] 用node写个爬虫
寻找爬取的目标
首先我们需要一个坚定的目标,于是找个一个比较好看一些网站,将一些信息统计一下,比如 url/tag/title/number...等信息
init(1, 2); //设置页数,现在是1-2页
async function init(startPage, endPage) {
for (let i = startPage; i <= endPage; i++) {
await getAndSaveImg(i);
}
.....
}
一般网站都会进行一些反爬虫处理,这时候就需要一个 ip 代理池进行 ip 伪装了.
网络请求
使用一个 nodejs 的模块 request,这个模块可以让 node 的 http 请求变的更加简单,同时支持 http/https 请求还可以将任何请求输出到文件流.
request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
使用 request 封装个方法进行请求
新建 utils/ajax.js
let request = require("request");
module.exports = {
handleRequestByPromise
};
function handleRequestByPromise(options) {
let op = Object.assign(
{},
{
url: "",
method: "GET",
encoding: null,
header: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
Referer: "https://www.meituri.com"
}
},
options
);
if (op.url === "") {
throw new Error("请求的url地址不正确");
}
const promise = new Promise(function(resolve, reject) {
request(op, (err, response, body) => {
if (err) reject(err);
if (response && response.statusCode === 200) {
resolve(body);
} else {
reject(`请求✿✿✿${url}✿✿✿失败`);
}
});
});
return promise;
}
cheerio
爬虫需要抓取页面上特定的信息.需要依据一些标识符去拿到想要的信息,不如 id.比如 class.cheerio 就是这么一个工具,将网站信息转化成可以直接用 jquery 的 dom 进行提取的一个模块.cheerio 的出现就是用于服务端需要对 dom 进行操作的地方.
基本使用
let cheerio = require('cheerio');
let $ = cheerio.load("<div id='helloworld'>hello world</div>", {ignoreWhitespace: true...})
options 用来进行一些特别的定制更多
选择器
基本和 jquery 一样
- $( selector, [context], [root] )
$(".helloworld").text();
属性操作
- .attr(name, value)
- .removeAtrr(name)
- .hasClass(className)
- .addClass(className)
- .remoteClass([className])
遍历
- .find(selector)
- .parent()
- .next()
- .prev()
- .siblings()
- .children( selector )
- .each( function(index, element) )
- .map( function(index, element) )
- .filter( selector )
- .filter( function(index) )
- .first()
- .last()
- .eq(i)
操作 DOM
- .append( content, [content, ...] )
- .prepend( content, [content, ...] )
- .after( content, [content, ...] )
- .before( content, [content, ...] )
- .remove( [selector] )
- .replaceWith( content )
- .empty()
- .html( [htmlString] )
- .text( [textString] )
其他
- $.html()
- $('ul').text()
- .toArray()
- .clone()
- $.root()
- $.contains( container, contained )
在项目中使用
let homeBody = await handleRequestByPromise({ url: pageImgSetUrl });
let $ = cheerio.load(homeBody);
let lis = $(".hezi li");
上面就是将获取的 html 数据通过 cheerio 转化后,可以直接使用$符号进行类似 dom 的使用方法.特别适合前端使用
iconv-lite
有些时候,获取到的数据是一些乱码,尤其是中文的情况.所以我们需要解决乱码的问题,iconv-lite 模块就可以解决这一问题.
homeBody = iconv.decode(homeBody,"GBK"); //进行gbk解码
如果乱码就在 cheerio.load()之前进行解码.(这次用的网站并没有乱码).原因是
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> //这里是utf-8
如果是 gbk 或者 gbk2312 等就需要解码了
爬取流程
- 找寻目标
- 控制台查看 dom 的信息存放或标识符(id,class,element)
- 爬取 title,url,tag,num 等信息进行存放
- 进行下载(如果只需要链接其实可以不下载,不过许多网站对图片外部引入有限制)
- 入库(mysql)
- 出个 html 进行图片查看(简易写真集网站)
初始化
还是创建一个本地服务器,异步没有使用 async 模块,而是直接使用 es6 的 async/await 语法.
let http = require("http");
let url = require("url");
let Extend = require("./Extend");
let xz = new Extend(1, 2);
http
.createServer((request, response) => {
let pathname = url.parse(request.url).pathname;
if (pathname !== "/favicon.ico") {
router(pathname)(request, response);
}
})
.listen(9527);
console.log("server running at http://127.0.0.1:9527/");
function router(p) {
let router = {
"/": (request, response) => {
response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
response.end();
},
"/xz": async (request, response) => {
response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
await xz.init(response);
response.end();
},
"/404": (request, response) => {
response.writeHead(404, { "Content-Type": "text/plain;charset=utf-8" });
response.end("404找不到相关文件");
}
};
!Object.keys(router).includes(p) && (p = "/404");
return router[p];
}
分析页面
直接右键在控制台中查看就好了,看看 class,id 什么,cheerio 实现的 jquery 的 dom 相关的 api 十分强大,直接$("")就行
进行网站的分析和抓取
开始进行网站数据的分析和爬取,如果乱码就在 cheerio 操作之前进行解码就行了,这样通过一个变量将爬取的数据全部保存起来.也可以创建相应的文件夹和 txt 文件进行保存(writeFile),还可以直接在这里就将数据保存到数据库.(看心情)
async getAndSaveImg(page) {
let pageImgSetUrl = ``;
if (page === 1) {
pageImgSetUrl = `${this.siteUrl}`;
} else {
pageImgSetUrl = `${this.siteUrl}${page}.html`;
}
let homeBody = await handleRequestByPromise({ url: pageImgSetUrl });
let $ = cheerio.load(homeBody);
let lis = $(".hezi li");
for (let i = 0; i < lis.length; i++) {
let config = {
href: lis
.eq(i)
.find("a")
.eq(0)
.attr("href"),
num: lis
.eq(i)
.find(".shuliang")
.text(),
title: lis
.eq(i)
.find(".biaoti a")
.text()
.replace(/\//, "")
};
config.childs = [];
let num = Number(config.num.substr(0, 2));
for (let j = 1; j <= num; j++) {
let link = config.href.replace(
this.collectUrl,
"https://ii.hywly.com/a/1/"
);
let a_link = `${link}${j}.jpg`;
config.childs.push(a_link);
}
this.all.push(config);
}
}
进行图片的下载
开始进行图片的下载,并且创建相应的文件夹进行保存
async downloadAllImg() {
let length = this.all.length;
for (let index = 0; index < length; index++) {
let childs = this.all[index].childs;
let title = this.all[index].title;
if (childs) {
let c_length = childs.length;
for (let c = 0; c < c_length; c++) {
if (!fs.existsSync(`mrw`)) {
fs.mkdirSync(`mrw`);
}
if (!fs.existsSync(`mrw/${title}`)) {
fs.mkdirSync(`mrw/${title}`);
}
await super.downloadImg(
childs[c],
`mrw/${title}/${title}_image${c}.jpg`
);
console.log(
"DownloadThumbsImg:",
title,
"SavePath:",
`mrw/${title}/${title} image${c}.jpg`
);
}
}
}
}
下载完之后存入数据库
下载 mysql 模块进行 mysql 数据库操作
const fs = require("fs");
const mysql = require("mysql");
const path_dir = "D:\\data\\wwwroot\\xiezhenji.web\\static\\mrw\\";
const connection = mysql.createConnection({
host: "xxxx",
port: "xxxx",
user: "xiezhenji",
password: "iJAuzTbdrDJDswjPN6!*M*6%Ne",
database: "xiezhenji"
});
module.exports = {
insertImg
};
function insertImg() {
connection.connect();
let files = fs.readdirSync(path_dir, {
encoding: "utf-8"
});
files.forEach((file, index) => {
let cover_img_path = `/mrw/mrw_${index + 1}/image_1`;
insert([
"美女",
file,
Number(files.length),
file,
cover_img_path,
`mrw/mrw_${index + 1}`,
`mrw_${index + 1}`
]);
});
}
function insert(arr) {
let sql = `INSERT INTO photo_album_collect(tags,name,num,intro,cover_img,dir,new_name) VALUES(?,?,?,?,?,?,?)`;
let sql_params = arr;
connection.query(sql, sql_params, function(err, result) {
if (err) {
console.log("[SELECT ERROR] - ", err.message);
return;
}
console.log("--------------------------SELECT----------------------------");
console.log(result);
console.log(
"------------------------------------------------------------\n\n"
);
});
}
Docs
-
声明:仅供学习,不可用于商业用途
[Nodejs] 用node写个爬虫的更多相关文章
- 初步学习nodejs,业余用node写个一个自动创建目录和文件的小脚本,希望对需要的人有所帮助
初步学习nodejs,业余用node写个一个自动创建目录和文件的小脚本,希望对需要的人有所帮助,如果有bug或者更好的优化方案,也请批评与指正,谢谢,代码如下: var fs = require('f ...
- 用Node+wechaty写一个爬虫脚本每天定时给女(男)朋友发微信暖心话
wechatBot 微信每日说,每日自动发送微信消息给你心爱的人 项目介绍 灵感来源 在掘金看到了一篇<用Node + EJS写一个爬虫脚本每天定时女朋友发一封暖心邮件>后, 在评论区偶然 ...
- 使用node写爬虫入门
最近看了node能做爬虫,所以就试了一下,一下是整个过程的记录 1.新建文件夹baidunews 2.在上边新建的文件夹下输入npm init进行初始化 3.初始化完成后下载需要的依赖包 npm in ...
- nodejs实现最简单的爬虫
本文将以抓取百度搜索结果中关键词的相关搜索为例子,教会大家以nodejs制作最简单的爬虫: 开始之前呢,先来个公众号求粉: 将使用的node模块及属性介绍: request: ...
- Node.js 使用爬虫批量下载网络图片到本地
图片网站往往广告众多,用Node.js写个爬虫下载图片,代码不长,省事不少,比手动一张张保存简直是天与地的区别.以前用Java也做过远程图片下载,但Node.js的下载速度更让人咂舌,这也是非阻塞式变 ...
- 读书笔记汇总 --- 用Python写网络爬虫
本系列记录并分享:学习利用Python写网络爬虫的过程. 书目信息 Link 书名: 用Python写网络爬虫 作者: [澳]理查德 劳森(Richard Lawson) 原版名称: web scra ...
- [原创]手把手教你写网络爬虫(4):Scrapy入门
手把手教你写网络爬虫(4) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 上期我们理性的分析了为什么要学习Scrapy,理由只有一个,那就是免费,一分钱都不用花! 咦?怎么有人扔西红柿 ...
- [原创]手把手教你写网络爬虫(5):PhantomJS实战
手把手教你写网络爬虫(5) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 大家好!从今天开始,我要与大家一起打造一个属于我们自己的分布式爬虫平台,同时也会对涉及到的技术进行详细介绍.大 ...
- [原创]手把手教你写网络爬虫(7):URL去重
手把手教你写网络爬虫(7) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 本期我们来聊聊URL去重那些事儿.以前我们曾使用Python的字典来保存抓取过的URL,目的是将重复抓取的UR ...
随机推荐
- 关于” 记一次logback传输日志到logstash根据自定义设置动态创建ElasticSearch索引” 这篇博客相关的优化采坑记录
之前写过一篇博客是关于记录日志的简单方式的 主要就是 应用->redis->logstash->elasticsearch 整个流程的配置方法和过程的 虽然我们部分线上应用使用 ...
- 使用Onenote & Evernote & VSC+Markdown构建个人笔记系统
Onenote & Evernote & VSC+Markdown构建个人笔记系统 umeowbing(转载请注明出处) 1 Why 笔记本太多,全部带着太重,查找起来也很麻烦-- 笔 ...
- Postman----基础使用篇(没有接口文档的情况下如何着手做接口测试)
[备注说明]内文中的图片由于页面的限制,图片显示不清晰,为了能更加的看清图片,请点击"图片",点击"右键"选择"在新标签页中打开图片",可查 ...
- 基于promtheus的监控解决方案
一.前言 鄙人就职于某安全公司,团队的定位是研发安全产品云汇聚平台,为用户提供弹性伸缩的云安全能力.前段时间产品组提出了一个监控需求,大致要求:平台对vm实行动态实时监控,输出相应图表界面,并提供警报 ...
- hystrix 结果缓存机制(5)
hystrix支持将一个请求结果缓存起来,下一个具有相同key的请求将直接从缓存中取出结果,减少请求开销.要使用hystrix cache功能 第一个要求是重写getCacheKey(),用来构造ca ...
- 频率学派与贝叶斯学派(先验分布与后验分布,MLE和MAP)
频率学派(古典学派)和贝叶斯学派是数理统计领域的两大流派. 这两大流派对世界的认知有本质的不同:频率学派认为世界是确定的,有一个本体,这个本体的真值是不变的,我们的目标就是要找到这个真值或真值所在的范 ...
- netcore程序部署到docker
1.基础准备 1. ubuntu 18.04 2. docker version 18.09 3. netcore 2.1 2.简介 自从netcore支持跨平台之后,以及现在很多公司都是采用容器化部 ...
- 程序员如何让自己 Be Cloud Native - 配置篇
前言 这是<程序员如何让自己 Be Cloud Native>系列文章的第二篇,从第一篇的反馈来看,有些同学反馈十二要素太形式主义,不建议盲目跟从.作者认为任何理论和技术都需要有自己的观点 ...
- 使用JS+Three.js+Echart开发商场室内地图客流信息统计功能
现在的商场管理者在管理商场的同时面临着一些无法避免的问题比如:人员监管不到位.效率低下.商场同质化严重,人流量少等.发现了这些问题作为开发人员的我们怎能视而不见,我们的责任就是发现问题解决问题,提供更 ...
- 如何在MySQL中查询每个分组的前几名【转】
问题 在工作中常会遇到将数据分组排序的问题,如在考试成绩中,找出每个班级的前五名等. 在orcale等数据库中可以使用partition语句来解决,但在mysql中就比较麻烦了.这次翻译的文章就是专门 ...