一、获取网页内容

nodejs提供了简便的方法帮助我们获取网页的整片内容。node的核心模块http模块即可发送请求,摘自node官网api:
http.request(options[.callback])
http.request(url[,options][,callback])

以豆瓣top250网站为例:豆瓣电影 Top 250 (douban.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const https = require('https')

let url = 'https://movie.douban.com/top250'
let req = https.request(url, res => {
let chunks = []
//监听data事件,获取传递过米的数据片段
//拼接数据片段
res.on('data',chunk => chunks.push(chunk))

res.on('end', () => {
//拼按所有的chunk,并转换成字符串
let htmlStr = Buffer.concat(chunks).toString('utf-8')
console.log(htmlStr);
})
})

req.end()

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const https = require('https')
const cheerio = require('cheerio')

let url = 'https://movie.douban.com/top250'
let req = https.request(url, res => {
let chunks = []
res.on('data',chunk => chunks.push(chunk))

res.on('end', () => {
let htmlStr = Buffer.concat(chunks).toString('utf-8')
let $ = cheerio.load(htmlStr)
$('.item .info .hd .title').each((index, item) => {
console.log($(item).text())
})
})
})

req.end()

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const https = require('https')
const cheerio = require('cheerio')

let url = 'https://movie.douban.com/j/search_tags?type=movie&source=index'
let req = https.request(url, {method:'get', headers: {
"Accept":"","Accept-Encoding":"",
"Accept-Language":"","Connection":"",
"Cookie": "viewed='35631064'; bid=UwHXnWLpcZg; gr_user_id=bf201205-1e3a-4131-8491-88253e67fb76; __gads=ID=749f4c4931ab025b-223da8c8c8db007b:T=1679058886:RT=1679058886:S=ALNI_MZRUmjknbTk54CTIvi5s1m_3-SA7A; ll='118303'; _vwo_uuid_v2=D52720B4D5A586B53BD688A3786124938|f87d4e04b1cd62572810de204fdd3eb5; __yadk_uid=dV04udAWkRjdUKLUIpCLx8JuGzQ4H4Ic; _pk_id.100001.4cf6=a77e2b4705c4ab5a.1680358419.; __gpi=UID=000009626405c239:T=1679058886:RT=1684638900:S=ALNI_Mb9EqpYZxZsGwCPw_b6iZflzNBXNQ; douban-fav-remind=1; Hm_lvt_16a14f3002af32bf3a75dfe352478639=1702295581; __utmc=30149280; __utmc=223695111; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1704346116%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D; _pk_ses.100001.4cf6=1; ap_v=0,6.0; __utma=30149280.988761868.1679058890.1704284347.1704346123.21; __utmb=30149280.0.10.1704346123; __utmz=30149280.1704346123.21.13.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utma=223695111.1604615225.1680358420.1704284347.1704346123.19; __utmb=223695111.0.10.1704346123; __utmz=223695111.1704346123.19.8.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/","Host":"","Referer":"","https":"//movie.douban.com/","Sec-Ch-Ua":"","Sec-Ch-Ua-Mobile":"","Sec-Ch-Ua-Platform":"","Sec-Fetch-Dest":"","Sec-Fetch-Mode":"","Sec-Fetch-Site":"","User-Agent":"","X-Requested-With":""
}}, res => {
let chunks = []
res.on('data',chunk => chunks.push(chunk))

res.on('end', () => {
let htmlStr = Buffer.concat(chunks).toString('utf-8')
console.log(JSON.parse(htmlStr));
})
})

req.end()

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
2
3
4
5
6
7
8
9
10
11
//导入selenium 库
const {Builder, By, Key, until,Button} = require('selenium-webdriver');

// require('chromedriver'); 如果是npm安装驱动需要导入chromedriver
(async ()=>{
// require('chromedriver'); //导入chrome浏览器 driver,不是npm安装驱动不需要导入chromedriver
const driver = new Builder().forBrowser('chrome').build()
await driver.get('')
//driver.quit() // 表示关闭浏览器
//driver.close() //表示关闭当前窗口
})()

这里引入了selenium最基础的方法:

  • Builder 对象:用于设置 WebDriver 的配置。通过 forBrowser() 方法指定浏览器类型,并通过 build() 方法生成 WebDriver 实例。

  • By 对象:用于选择网页中的元素,常用的方法包括 idnameclassxpathcss 等。

  • Key 对象:表示键盘上的按键,用于模拟键盘操作,如回车键、Tab 键等。

  • until 对象:用于等待某些条件的出现,如等待页面加载完成、等待元素出现等。

  • Button 对象:表示鼠标上的按键,用于模拟鼠标操作,如左键、右键、滚轮等。

    更多API

    选择器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    driver.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
    18
    driver.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
    11
    driver.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
    11
    let options = driver.manage()//获得options对象

    options.addCookie({name: 'name', value:'value'})

    options.deleteAllCookies()

    cookiesoptions.deleteCookie(name) //删除所有

    options.getCookie(name) //按照name删除

    options.getCookies() //拿到name字段的cookie值,为promise对象
    1
    2
    3
    4
    5
    6
    let 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
    17
    const 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const mysql = require('mysql')
let options = {

host: "localhost", //主机地址
user: "root", //用户名
password: "123123",
port: "3306",//端口号,可选
database: "mall" /数据库名
}
//创建与数据库连接的对象
let con = mysql.createConnection(options)
con.connect((err) => {
if(err) {
console.log(err)
}else {
console.log("连接成功")
}
})

封面图片链接https://ts1.cn.mm.bing.net/th/id/R-C.4d20f5962fda5344d5ccd24f617c00fb?rik=o5PglvR6Vg1X0A&riu=http%3a%2f%2fimage.hnol.net%2fc%2f2016-10%2f08%2f13%2f201610081352257411-2127595.jpg&ehk=gYdCn243RGotUkh0qzsI08x9U6me0TgcRaAGn9I78jw%3d&risl=&pid=ImgRaw&r=0