node.js爬虫
一、获取网页内容
nodejs提供了简便的方法帮助我们获取网页的整片内容。node的核心模块http模块即可发送请求,摘自node官网api:
http.request(options[.callback])
http.request(url[,options][,callback])
以豆瓣top250网站为例:豆瓣电影 Top 250 (douban.com)
1 | const https = require('https') |
node运行,输出如下图:
首先创建了一个 https.request(url, callback)
请求对象,其中 url
参数是请求的目标 URL,callback
是在请求完成后执行的回调函数。
在回调函数中,创建了一个空数组 chunks
,用于存储接收到的数据片段。
接下来,使用 res.on('data', callback)
监听 ‘data’ 事件,当有新的数据片段到达时,会触发该事件,并将数据片段作为参数传递给回调函数。在回调函数中,将接收到的数据片段存储到 chunks
数组中。
继续监听 ‘end’ 事件,在所有数据片段接收完毕后触发该事件,并执行回调函数。在回调函数中,通过 Buffer.concat(chunks).toString('utf-8')
将接收到的所有数据片段拼接起来,并转换为 UTF-8 编码的字符串。
最后,调用 req.end()
发送请求,表示请求的发送完毕。
有 req.end()
发送才会终止。
二、cheerio库解析html
cheerio 是为服务器特别定制的,快速、灵活的jQuery核心实现,是jQuery的子集。
cheerio可以帮助我们解析HTML代码,并且可以直接使用jQuery一样的api。
首先需要引入cheerio库:
1 | npm i cheerio -S |
在上例代码的基础上,引入cheerio
库,写一个爬取豆瓣电影名的方法:
1 | const https = require('https') |
Cheerio 的 load
方法可以将 HTML 字符串转换成一个可操作的 DOM 树,返回一个类似于 jQuery 对象的实例。用$
接收这个jQuery对象,并用类选择器定位所要的html语句。因为网页中有多个电影名,每个电影名所在的html语句有相同的类名,所以用each
遍历截取的html对象,用.text()
来获取html语句里的文本。
语法如下:
$(selector).each(callback)
node运行,输入如下:
伪造请求头获取接口内容
对于前后端分离的网站,截取html内容往往不能满足我们的需求,我们需要爬取网站接口里的信息。
以豆瓣电影网为例:https://movie.douban.com/
在标头处获取url和请求方式:
下拉找到请求标头,复制其信息,可以复制到请求/响应头转JSON工具让其转成JSON格式更方便:
代码示例:
1 | const https = require('https') |
https.request(url,(method),(headers:{}))
方法,method和请求头headers都是可选参数,method默认为GET
方法
node输出:
三、Selenium网页自动化操作
Selenium是广泛使用的模拟浏览器运行的库,它是一个用于Web应用程序测试的工具。 Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,并且支持大多数现代 Web 浏览器。下面就进入正式的学习阶段。
下载浏览器驱动
在设置里查看自己的浏览器版本,我的是Chrome的120.0.6099.200(正式版本) (64 位)
打开Chrome驱动网页 (需要借助一些工具才能到达此页),选择对应的版本,如果没有对应的版本,选择最近的一个版本即可。
点击进入后根据自己的操作系统选择版本,Windows就下载win32版本:
下载好后解压,里面会有一个exe文件,但直接运行不会有什么效果
将这个exe文件放在你的代码文件目录下,如果你不想每次都添加到工作目录,可以将这个exe的文件路径添加到环境变量中去。
你也可以选择使用npm来安装,但有几率安装失败
1 | npm install chromedriver |
安装selenium
基本使用
在终端输入:
1 | npm install selenium-webdriver |
等待安装完成,使用下面的代码进行测试,如果能弹出浏览器,说明安装成功
1 | //导入selenium 库 |
这里引入了selenium最基础的方法:
Builder
对象:用于设置 WebDriver 的配置。通过forBrowser()
方法指定浏览器类型,并通过build()
方法生成 WebDriver 实例。By
对象:用于选择网页中的元素,常用的方法包括id
、name
、class
、xpath
、css
等。Key
对象:表示键盘上的按键,用于模拟键盘操作,如回车键、Tab 键等。until
对象:用于等待某些条件的出现,如等待页面加载完成、等待元素出现等。Button
对象:表示鼠标上的按键,用于模拟鼠标操作,如左键、右键、滚轮等。更多API
选择器
1
2
3
4
5
6
7
8
9
10
11
12driver.findElement(By.name('btnG'));
driver.findElement({id:'btnG'});
findElements //查找多个元素By.className(classname)
By.css(selector) //通过 CSS Selector 查找元素
By.id(id)
By.name(name) //通过 Name 属性查找元素。
By.linkText(text) //通过链接文本查找元素。
By.partialLink(text) //通过部分链接文本查找元素。
By.xpath() //通过 XPath 查找元素。
By.js() //通过 JavaScript 查找元素。属性获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18driver.getPageSource().then(function(souce) {console.log(souce);//获取代码
driver.getTitle().then(a=>{console.log(a)});//获取网页标题
driver.getCurrentUrl().then(a=>{console.log(a)});//获取当前url
//element为web元素对象,为findelement()的返回对象element.getText().then(b=>{console.log(“text”,b)})
//返回里面没有被隐藏的文字(不带标签)
element.getTagName().then(a=>{console.log('getTagName',a)})
//返回标签名
element.getId().then(a=>{console.log(“ID”,a)})
//返回这个element服务器分配的不透明id
elements.getCssValue().then(a=>{console.log('getCssValue',a)})
//返回该element的CSS属性
//其他属性:element.getAttribute(“class”).then(b=>{console.log(b)})操作
1
2
3
4
5
6
7
8
9
10
11driver.findElement({css:css}).click()//鼠标左键单击
driver.findElement({css:css}).clear(); //清空input
driver.findElement({css:css}).sendKeys('txt');//输入input
driver.takeScreenshot().then() //返回页面png截图
driver.findElement({css:css}).takeScreenshot().then() //返回元素png截图
driver.excuteScript("document.getElementByTagName('body')[0].scrollTop='8000'")//窗口滚动条-下拉滚动条操作
driver.actions().mouseMove(el).perform() //鼠标悬停操作options对象
1
2
3
4
5
6
7
8
9
10
11let options = driver.manage()//获得options对象
options.addCookie({name: 'name', value:'value'})
options.deleteAllCookies()
cookiesoptions.deleteCookie(name) //删除所有
options.getCookie(name) //按照name删除
options.getCookies() //拿到name字段的cookie值,为promise对象navigate对象
1
2
3
4
5
6let nav = driver.navigate()//获得navigate对象
///nav有四个方法分别为:
nav.back();//后退
nav.forward();//前进
nav.refresh();//刷新
nav.to(url);//跳转到url下面示例一个打开bing自动搜索壁纸并点击截图的自动化程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const fs = require('fs')
const {Builder, By, Key, until,Button,Actions} = require('selenium-webdriver');
(async ()=>{
// require('chromedriver'); //导入chrome浏览器 driver,不是npm安装驱动不需要导入chromedriver
//这里我使用的chrome
const driver = new Builder().forBrowser('chrome').build()
await driver.get('https://cn.bing.com/') //想要打开的网址
await driver.findElement(By.css('#sb_form_q')).sendKeys('bing壁纸4k', Key.ENTER);//输入input
await driver.findElement(By.css('#b-scopeListItem-images')).click()
await driver.findElement(By.css('.img_cont > img:first-child')).click()
const actions = driver.actions({ bridge: true })
await actions.contextClick(await driver.findElement(By.css('body')).click()).perform(); // 右键单击
const screenshot = await driver.takeScreenshot(); // 截图
fs.writeFileSync('screenshot.png', screenshot, 'base64'); // 将截图数据写入图片文件
})()更多的selenium的api可以在他的npm官网找到:selenium-webdriver
selenium应对反爬虫
大部分网站会有反爬机制,通过cheerio库或者截取html信息无法获取全部信息。且过多的爬虫会被网站封杀ip,selenium能把我们包装成正常访问网站的浏览器用户,帮助我们更好的爬取我们需要的数据。
四、nodejs连接数据库
爬虫的最终目标的将数据存入数据库,nodejs也提供了相应的模块方便我们操作,以mysql为例
node.js连接数据库需要先安装mysql包npm install mysql
代码示例:
1 | const mysql = require('mysql') |