今天,我们来用node
实现一个多页面应用的爬虫操作,在进行爬虫操作之前,我们需要了解一些基本知识
什么是node?
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它使用了事件驱动、非阻塞 I/O 模型,使得 JavaScript 代码可以在服务器端高效运行。
我们要知道node不是一门编程语言!
Node.js 的主要特点包括:
- 事件驱动:Node.js 使用事件驱动的编程模型,通过回调函数来处理异步操作。
- 非阻塞 I/O:Node.js 中的 I/O 操作(如文件读写、网络请求等)是非阻塞的,不会阻塞后续代码的执行。
- 单线程:Node.js 是单线程的,但通过事件循环和回调机制来实现并发处理。
- 模块系统:Node.js 拥有强大的模块系统,可以方便地导入和导出模块。
- 社区活跃:Node.js 有一个活跃的社区,提供了丰富的第三方库和工具。
Node.js 常用于构建高性能的 Web 服务器、后端应用程序、实时数据处理等。它也适用于 IOT(物联网)、移动应用开发和命令行工具等领域。
我们先来了解一下node
的一些基本的语法!
模块:例如:console
在 Node.js 中,模块是一种组织代码的方式。模块可以将相关的功能和代码封装在一起,使代码更具有可维护性和可重用性。
每个模块都可以导出一些函数、对象或变量,其他模块可以通过导入这个模块来使用其中导出的内容。
我们经常使用的一个指令console.log()
console
是node
里面的一个模块,console
是一个对象,后面可以接很多种方法!
Node.js 的 console
模块提供了在控制台上打印消息、调试信息和错误的方法。它是一个内置模块,用于输出日志、数据和其他信息,以便在开发和运行过程中进行调试和监控。
以下是 console
模块常用的方法:
console.log()
: 用于打印普通消息或数据到控制台。console.error()
: 用于打印错误消息到控制台。console.warn()
: 用于打印警告消息到控制台。console.info()
: 用于打印信息性消息到控制台。console.debug()
: 用于打印调试消息到控制台。
具体可以在官方文档:console 控制台 | Node.js v20 文档 (nodejs.cn)查看!
我们可以通过使用 console
模块,可以在 Node.js 应用程序中方便地输出各种类型的消息,帮助调试代码、监控程序的运行状态和了解程序的行为等一系列操作。
我们在js
有一些方法!其实在node
中也是可以执行出来的!例如:
js
console.log(Date);
console.log(Math);
输出:
[Function: Date]
Object [Math] {}
当然在js
中有一个定时器,这个也是可以在node
中使用的!
js
setTimeout(()=>{
console.log('setTimeout');
},2000)
输出:
setTimeout
还有一个setInterval
和setImmediate
js
console.log(setInterval);
console.log(setImmediate);
输出:
[Function: setInterval]
[Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
}
这些js
中的定时器在node当中都是可以识别的!当然在浏览器中还有一个定时器 requestAnimationFrame
,这个是浏览器环境下的一个函数,这个函数在node
中是无法识别的!
requestAnimationFrame
是浏览器环境下的一个类似定时器的函数,时间是固定的,是根据电脑屏幕的刷新率来设定的,时间是不需要我们去手动设置的。
要想实现后端的功能,与我们的操作系统打交道是必不可少的!我们再介绍两个语句
js
console.log(__dirname)//读取到当前文件夹的绝对路径,当前文件所处的文件夹的绝对路径;
console.log(__filename);//读取到某个文件所在的绝对路径
输出:
C:\Desktop\codespace\node\spider\base
C:\Users\www16\Desktop\codespace\node\spider\base\1.js
这种语句是js
中没有的内容,还有一个语句可以查看当前的进程!
js
console.log(process);
大家可以新建一个文件夹尝试一下!
argv指令+剪刀石头布Demo
在node
当中有一个argv
指令,可以接收人为输入的指令!例如:
js
console.log(process.argv);
我们在终端这样输入:node 1.js hello
输出:
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\www16\\Desktop\\codespace\\node\\spider\\base\\1.js',
'hello'
]
我们可以通过这样的语句获取到我们输入的最后一条指令!
js
process.argv[process.argv.length - 1]
有了这样一个思路,我们就可以做一个简单的剪刀石头布demo了!
js
let player = process.argv[process.argv.length - 1]
//用电脑随机生成一个
let arr = ['rock','scissors','paper']
let index = Math.floor(Math.random()*arr.length)
let computer = arr[index]
//比较规则
if(computer === player)
{
console.log('平局');
}else if(
(computer==='rock'&& player==='paper')||
(computer==='scissors'&& player==='rock')||
(computer==='paper'&& player==='scissors')
){
console.log('你赢了');
}else{
console.log('你输了');
}
我们就可以试试这样一个石头剪刀布游戏是否成功!
node
PS C:\Users\www16\Desktop\codespace\node\spider\base> node 2.js rock
你输了
PS C:\Users\www16\Desktop\codespace\node\spider\base> node 2.js rock
平局
npm库
node
还有一个npm
库!也就是装轮子!我们可以通过npm
安装很多大佬封装好的功能!
我们首先要做的就是对项目进行初始化!在终端运行下述指令!
node
npm init
初始化的过程中我们需要做一个选择,这个大家按需选择就可以!
我们可以创建一个index.js
入口文件! 入口文件是应用程序开始执行的文件。
我们有一个仓库网站:npm | Home (npmjs.com)
在这个网站,我们可以找到我们需要的功能!找到安装的指令,我们只需要运行一下相应的指令,我们就可以将相应的功能包安装到我们的项目当中!
大家可以会遇到下载速度慢等问题!我们就需要对npm
库进行换源!
我们有很多国内的厂商会把npm
库的数据拷贝下来,方面国内用户的使用,并且实时更新,所以我们就可以通过一些指令将下载源换到我们国内厂商的地址,这样下载速度也会提高!
我们可以使用这个指令查看我们当前的下载源:(在终端运行)
node
npm config get registry
我们如何换源呢?例如:
node
npm config set registry 地址
这是国内大佬总结的一些npm
源镜像!
npm 官方原始镜像网址是:registry.npmjs.org/ 淘宝 NPM 镜像:旧:registry.npm.taobao.org 新:registry.npmmirror.com 阿里云 NPM 镜像:npm.aliyun.com 腾讯云 NPM 镜像:mirrors.cloud.tencent.com/npm/ 华为云 NPM 镜像:mirrors.huaweicloud.com/repository/... 网易 NPM 镜像:mirrors.163.com/npm/ 中科院大学开源镜像站:mirrors.ustc.edu.cn/ 清华大学开源镜像站:mirrors.tuna.tsinghua.edu.cn/
大家可以挑一个合适的进行使用!
我们装好npm
库中的包之后,我们可以在node_modules
文件中看到我们下载的源代码,这个文件就是存放各种依赖包的位置(第三方的包)。
下载好之后,我们就可以引入并且使用相应包的功能了!
接下来,我们今天来尝试一下使用node
来写一个多页面应用爬虫!
node多页面应用爬虫
首先,我们可以拿一个豆瓣Top250网站作为我们的目标网址:movie.douban.com/top250
就比如,我们要把第一页的25个电影拿到!
首先我们新建一个文件夹spider
,再用npm init
初始化项目!
再新建一个index.js
文件作为入口文件!
我们要用到一个node
自带的一些模块:https
超文本传输协议中的get
方法!https 安全超文本传输协议 | Node.js v20 文档 (nodejs.cn)
所以我们再index.js文件中干第一个操作!我们可以看官方文档的语法!
js
const https = require('https')
https.get('https://movie.douban.com/top250',(res)=>{
})
在官方文档中这样描述的
可以看到对于回调函数中的res
有一个on
方法!这个方法的功能是监听数据的读取
于是乎,我们的代码就可以写成这样了!
js
const https = require('https')
https.get('https://movie.douban.com/top250',(res)=>{
res.on('data',(chunk)=>{
console.log(chunk)
})
})
我们可以使用console.log(chunk);
输出的是十六进制的数据。
我们要的不是这样的数据,我们可以使用toString
方法或者chunk+''
就可以拿到一个源代码的数据
console.log(chunk+'');
这样其实拿到的就是豆瓣页面上的源代码数据!因为数据过长,所以我们现在的代码是进行多次读取的,是一个缝合怪的结果!
js
const https = require('https')
https.get('https://movie.douban.com/top250',(res)=>{
let html = ''
res.on('data',(chunk)=>{
console.log(chunk +'')
html += chunk
})
})
所以,我们就可以用一个html
变量去把数据拿着自动拼接拿到的数据!我们怎么判断数据拿完了呢?
再res.on
方法中可以监听一个end
关键字,来判断数据是否获取完毕!
js
res.on('end',()=>{
//源代码获取完毕!
})
接下来,我们就是读取到源代码中的我们想要的数据!在以前js
的语法中,我们用的是document
获取页面的Dom结构,但是在node
中不行!doucument
是浏览器赋予的,node
里面不能写!那我们在node
中怎么操作html
呢?
这里我们就需要使用npm
库中的一个cheerio
包了!cheerio - npm (npmjs.com)
这个包,就允许我们在node
环境下操作html
了
所以我们接下来的步骤就是使用npm
安装这个包!
npm
npm i cheerio
接下来,我们这样使用cheerio
,
js
const cheerio = require('cheerio')
const https = require('https')
https.get('https://movie.douban.com/top250',(res)=>{
let html = ''
res.on('data',(chunk)=>{
html += chunk
})
res.on('end',()=>{
//源代码获取完毕!
const $ = cheerio.load(html)
// 定义一个数组 存储数据
const result = []
//我们观察源代码,可以知道我们要的数据是来自li .item中的 .info .title和.info .bd .retring_num和.pic img 根据cheerio官方文档的用法有一个each遍历方法,接下来我们这样写
$('li .item').each(function(){
// 拿到标题 找到.info容器下面的.title
const title = $('.info .title',this).text()
// 拿到评分
const star = $('.info .bd .rating_num',this).text()
//拿到电影的图片,取.pic下面的img标签,我们读属性用attr
const pic = $('.pic img',this).attr('src')
//把数据放入到数组当中,数据放入对象当中存入数组,这是解构语法
result.push(
{
title,
star,
pic
}
)
})
//打印数据
console.log(result);
})
})
写到这里,我们就可以看到我们拿到的数据了!
接下来,我们就需要把数据写入到本地当中,在node
当中有一个fs
模块,里面有一个方法writeFile
,我们可以用JSON.stringify(result)
将数据转换为JSON
格式,这个方法有三个参数
第一个参数是:写入位置
第二个参数是:JSON.stringify(result)
第三个参数是:一个回调函数,回调函数有两个参数(err,data)
,如果err
有值就是写入失败,如果没有值就是写入成功!所以现在我们的代码写成这样
js
const https = require('https')
const cheerio = require('cheerio')
const fs = require('fs')//node 里面自带的fs模块 与文件操作
https.get('https://movie.douban.com/top250',(res)=>{
//因为数据过长,这个data会反复执行的
let html = ''
res.on('data',(chunk)=>{
html += chunk
})
res.on('end',()=>{
//源代码获取完毕
const $ = cheerio.load(html)
// 定义一个数组,存储数据
const result = []
$('li .item').each(function(){
// 拿到标题
const title = $('.info .title',this).text()
// 拿到评分
const star = $('.info .bd .rating_num',this).text()
//拿到电影的图片,取.pic下面的img标签,我们读属性用attr
const pic = $('.pic img',this).attr('src')
//把数据放入到数组当中,数据放入对象当中存入数组,这是解构语法
result.push(
{
title,
star,
pic
}
)
})
console.log(result);
fs.writeFile('./list.json', JSON.stringify(result),(err,data)=>{
if(err)
{
throw err
}
console.log('文件写入成功!');
})
})
})
运行之后,我们就会发现,在我们的目录中出现了一个新的文件list.json
这个文件内容默认是不换行的,我们可以右键格式化一下:
于是我们就拿到最后的数据了
最后
我们这个node
爬虫,只适用于那些传统的多页面应用网址,如果使用的是vue
等其他框架编写的网站是无法用我们这个爬虫取爬取数据的,不过大家也可以使用这个豆瓣网站进行尝试!
如果,你觉得这篇文章有帮助的话,可以帮博主点赞+评论+收藏,三连一波!感谢!
往后,我还会持续输出vue相关的文章,如vue路由原理,node相关的内置模块,koa的使用等等文章,感兴趣的小伙伴可以关注一波!
代码以上传至个人Github:一个修远君的库 (github.com)