Article November 19, 2023

Node.js爬虫使用

Words count 30k Reading time 27 mins. Read count 0

1. 选择合适的爬虫库

在选择 Node.js 爬虫库时,需要根据项目需求考虑以下几个方面:

  1. Cheerio: 适用于简单 HTML 解析,不执行 JavaScript。
  2. Puppeteer: 用于处理动态网页,支持 JavaScript 执行。
  3. Axios: 用于发送简单 HTTP 请求,常与其他库结合使用。
  4. fs: 模块用于处理文件系统操作。

在选择时需综合考虑并发处理、反爬虫对策、可维护性和法律道德等因素。综合使用这些库,可以更灵活地构建高效的爬虫系统。

2. 库的用法

1. 发起HTTP请求

使用Axios发送HTTP请求的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const axios = require('axios');

// 发起GET请求
axios.get('https://example.com/api/data')
.then(response => {
console.log(response.data); // 响应数据
})
.catch(error => {
console.error('Error:', error);
});

// 发起 POST 请求
axios.post('https://jsonplaceholder.typicode.com/posts', {
title: 'foo',
body: 'bar',
userId: 1
})
.then(response => {
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error);
});

2. 操作浏览器

Puppeteer 是一个强大的库,用于处理动态网页,以下是一些基本用法和关键特点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const puppeteer = require('puppeteer');

(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

// 在页面上执行 JavaScript
const title = await page.evaluate(() => {
return document.title;
});

console.log('Page Title:', title);

// 截图和生成PDF
await page.screenshot({ path: 'screenshot.png' });
await page.pdf({ path: 'example.pdf', format: 'A4' });

// 处理表单和交互
await page.type('input[name="username"]', 'your_username');
await page.type('input[name="password"]', 'your_password');
await page.click('input[type="submit"]');

await browser.close();
})();

3. 解析HTML

Cheerio 是一个在服务器端运行的、基于 jQuery 核心实现的库,用于解析和操作 HTML 文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const cheerio = require('cheerio');
const htmlString = '<div><p>Hello, Cheerio!</p></div>';

// 将 HTML 字符串加载到 Cheerio
const $ = cheerio.load(htmlString);

// 使用选择器语法查找元素
const textContent = $('div p').text();
console.log('Text Content:', textContent);

// 遍历所有 p 元素并输出它们的文本内容
$('p').each((index, element) => {
console.log(`Paragraph ${index + 1}: ${$(element).text()}`);
});

// 获取第一个 a 元素的 href 属性
const href = $('a').first().attr('href');
console.log('Link Href:', href);

4. 处理数据

文件系统操作示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const fs = require('fs');

// 读取文件
fs.readFile('example.txt', 'utf-8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
} else {
console.log('Read data from file:', data);
}
});

// 写入文件
const dataToWrite = 'Hello, World!';
fs.writeFile('example.txt', dataToWrite, 'utf-8', (err) => {
if (err) {
console.error('Error writing file:', err);
} else {
console.log('Data written to file successfully.');
}
});

// 追加数据到文件
const dataToAppend = '\nAppending additional data.';
fs.appendFile('example.txt', dataToAppend, 'utf-8', (err) => {
if (err) {
console.error('Error appending to file:', err);
} else {
console.log('Data appended to file successfully.');
}
});

// 删除文件
fs.unlink('example.txt', (err) => {
if (err) {
console.error('Error deleting file:', err);
} else {
console.log('File deleted successfully.');
}
});

3. 实际案例

1. 爬取某网站的数据

一个基本的示例,爬取网站数据并保存到文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const axios = require("axios");
const fs = require("fs");
const cheerio = require("cheerio");

async function getLinks(url) {
try {
// 发送 GET 请求获取网页内容
const response = await axios.get(url);

// 使用 cheerio 解析 HTML
const $ = cheerio.load(response.data);
const links = [];

// 遍历匹配元素,提取链接
$(".sp-link a").each((index, element) => {
const href = $(element).attr("href");
if (href) {
links.push(href);
}
});

return links;
} catch (error) {
console.error(`获取链接时出错: ${error.message}`);
return []; // 返回空数组以避免错误传播
}
}

async function getItemData(url) {
try {
// 发送 GET 请求获取网页内容
const response = await axios.get(url);

// 使用 cheerio 解析 HTML
const $ = cheerio.load(response.data);

// 提取标题
const title = $("div.sp-title h1").text();

// 提取视频链接
const videoUrlMatch = $("p.videoBox").attr("data-src");

if (videoUrlMatch) {
const videoUrl = videoUrlMatch;
return { label: title, value: videoUrl };
} else {
throw new Error("无法提取视频链接。");
}
} catch (error) {
console.error(`获取或解析数据时出错: ${error.message}`);
return null; // 或者根据需要处理错误
}
}

async function main() {
const url = "your_target_url_here"; // 请替换为你的目标网址
const allVideoLinks = [];

try {
const links = await getLinks(url);

for (let i = 0; i < links.length; i++) {
const itemData = await getItemData(links[i]);
console.log(`${i + 1}/${links.length}`);
allVideoLinks.push(itemData);
}

// 将结果写入文件
fs.writeFileSync(
"videoList.txt",
JSON.stringify(allVideoLinks.filter((item) => !!item))
);

console.log("数据提取完成。");
} catch (error) {
console.error(`主程序出错: ${error.message}`);
}
}

main();

3. 进阶技巧

1. 处理异步操作

在爬虫中,异步操作是常见的需求,可以使用 async/await 或者 Promise 来处理异步任务。

2. 使用代理和反爬虫技术

使用代理和反爬虫技术是爬虫工程中常用的手段,以绕过一些限制和保护机制。

3. 定时任务和调度

通过定时任务和调度来执行爬虫任务,确保数据的及时更新。

4. 最佳实践

1. 代码结构和模块化

良好的代码结构和模块化设计有助于提高代码的可维护性和可扩展性。

2. 错误处理和日志记录

健壮的错误处理和详细的日志记录是构建可靠爬虫系统的重要组成部分。

3. 隐私和安全考虑

爬虫应遵循隐私和法律规定,确保不侵犯他人的权益,并采取措施防范安全风险。

5. 总结

以上是使用 Node.js 构建爬虫的一些关键知识点,涵盖了选择爬虫库、库的用法、实际案例、进阶技巧和最佳实践。通过综合运用这些知识,可以构建出高效、稳定且可维护的爬虫系统。

0%