用 Node.js 编写一个简单网页爬虫
用 Node.js 编写一个简单网页爬虫:从零开始入门
引言/概述
随着互联网数据的爆炸式增长,网络爬虫(Web Crawler)成为获取公开数据的重要工具。无论是用于数据分析、内容聚合,还是市场调研,爬虫都能帮助我们高效地从网页中提取结构化信息。Node.js 凭借其非阻塞 I/O 模型和丰富的生态库,成为构建轻量级爬虫的理想选择。
本文将带领你从零开始,使用 Node.js 编写一个简单的网页爬虫。我们将涵盖环境准备、发送 HTTP 请求、解析 HTML、提取目标数据、处理异常以及遵守爬虫礼仪等关键环节。最终实现一个能够抓取某新闻网站标题列表的小型爬虫程序。即使你是初学者,也能通过本文掌握爬虫的基本原理与实现方法。
核心内容
准备工作:安装必要依赖
在开始编写代码之前,我们需要安装几个关键的 Node.js 包:
axios:用于发送 HTTP 请求,比原生http模块更简洁。cheerio:类似 jQuery 的服务器端 HTML 解析库,用于提取 DOM 元素。fs(内置模块):用于将抓取的数据保存到本地文件。
首先,创建一个新的项目目录并初始化 npm:
mkdir simple-crawler
cd simple-crawler
npm init -y
然后安装依赖:
npm install axios cheerio
注意:本文示例以抓取公开且允许爬取的网站为目标(如某些新闻聚合页)。请务必遵守目标网站的
robots.txt协议,并避免对服务器造成过大压力。
发送 HTTP 请求获取网页内容
我们使用 axios 向目标 URL 发起 GET 请求,获取网页的 HTML 源码。以下是一个基础示例,抓取一个假设的新闻列表页面(例如:https://example-news.com):
// crawler.js
const axios = require('axios');
async function fetchPage(url) {
try {
const response = await axios.get(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; SimpleCrawler/1.0)'
}
});
return response.data; // 返回 HTML 字符串
} catch (error) {
console.error('请求失败:', error.message);
return null;
}
}
// 示例调用
const url = 'https://example-news.com';
fetchPage(url).then(html => {
if (html) {
console.log('成功获取页面,长度:', html.length);
}
});
这里我们设置了 User-Agent 头,模拟浏览器访问,避免被部分网站识别为机器人而拒绝请求。
使用 Cheerio 解析 HTML 并提取数据
获取 HTML 后,下一步是解析并提取我们需要的信息。假设目标页面的新闻标题都包裹在 <h2 class="title"> 标签中,我们可以使用 cheerio 进行选择和遍历:
const cheerio = require('cheerio');
function extractTitles(html) {
const $ = cheerio.load(html);
const titles = [];
$('h2.title').each((index, element) => {
const title = $(element).text().trim();
if (title) {
titles.push(title);
}
});
return titles;
}
cheerio.load() 将 HTML 字符串加载为可操作的 DOM 对象,之后就可以像使用 jQuery 一样使用 CSS 选择器(如 $('h2.title'))来定位元素。
整合流程:构建完整的爬虫函数
现在我们将上述步骤整合成一个完整的爬虫函数,并添加数据保存功能:
const fs = require('fs').promises;
async function crawlNews(url, outputFile = 'news_titles.txt') {
console.log(`正在抓取: ${url}`);
const html = await fetchPage(url);
if (!html) {
console.log('无法获取页面内容,终止爬取');
return;
}
const titles = extractTitles(html);
console.log(`共提取到 ${titles.length} 条新闻标题`);
// 将标题写入文件
const content = titles.join('\n');
await fs.writeFile(outputFile, content, 'utf8');
console.log(`数据已保存至 ${outputFile}`);
}
// 启动爬虫
const targetUrl = 'https://example-news.com';
crawlNews(targetUrl);
运行此脚本后,你将在项目根目录下看到一个 news_titles.txt 文件,其中包含所有抓取到的新闻标题。
处理常见问题与增强健壮性
实际爬虫开发中会遇到各种问题,以下是几个关键点:
1. 错误重试机制
网络请求可能因超时或临时故障失败。我们可以添加简单的重试逻辑:
async function fetchPageWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await axios.get(url, { timeout: 5000 });
return response.data;
} catch (error) {
console.warn(`第 ${i + 1} 次尝试失败:`, error.message);
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试
}
}
}
2. 遵守 robots.txt 与爬虫礼仪
负责任的爬虫应尊重网站的 robots.txt 规则。虽然本文不深入实现自动解析 robots.txt,但建议手动检查目标网站的该文件(如 https://example.com/robots.txt),确认是否允许爬取目标路径。
此外,应控制请求频率,避免对服务器造成压力。可在请求之间加入延迟:
await new Promise(resolve => setTimeout(resolve, 1000)); // 每次请求间隔1秒
3. 处理动态内容(进阶)
如果目标网站使用 JavaScript 动态加载内容(如 React/Vue 应用),axios 获取的 HTML 可能不包含完整数据。此时需使用 Puppeteer 等无头浏览器工具。但出于简单性,本文聚焦于静态页面爬取。
完整代码示例
以下是整合后的完整爬虫代码:
// simple-crawler.js
const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs').promises;
async function fetchPage(url) {
try {
const response = await axios.get(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; SimpleCrawler/1.0)'
},
timeout: 5000
});
return response.data;
} catch (error) {
console.error('请求失败:', error.message);
return null;
}
}
function extractTitles(html) {
const $ = cheerio.load(html);
const titles = [];
$('h2.title').each((index, element) => {
const title = $(element).text().trim();
if (title) {
titles.push(title);
}
});
return titles;
}
async function crawlNews(url, outputFile = 'news_titles.txt') {
console.log(`正在抓取: ${url}`);
const html = await fetchPage(url);
if (!html) {
console.log('无法获取页面内容,终止爬取');
return;
}
const titles = extractTitles(html);
console.log(`共提取到 ${titles.length} 条新闻标题`);
const content = titles.join('\n');
await fs.writeFile(outputFile, content, 'utf8');
console.log(`数据已保存至 ${outputFile}`);
}
// 使用示例(请替换为真实可爬取的URL)
const targetUrl = 'https://example-news.com';
crawlNews(targetUrl);
⚠️ 注意:请将
targetUrl替换为你有权爬取的真实网站 URL。切勿对禁止爬取或敏感网站发起请求。
总结
通过本文,我们从零开始构建了一个基于 Node.js 的简单网页爬虫。核心流程包括:使用 axios 发起 HTTP 请求获取 HTML、利用 cheerio 解析并提取目标数据、最后将结果保存到本地文件。同时,我们也探讨了错误处理、请求节流、遵守网络礼仪等实践要点。
虽然这个爬虫功能基础,但它为更复杂的爬虫系统奠定了基础——你可以在此之上扩展多页面爬取、数据去重、数据库存储、定时任务等功能。然而,请始终牢记:合法合规是爬虫开发的前提。在抓取任何网站前,务必确认其是否允许自动化访问,并控制请求频率,做一个负责任的数据使用者。
Node.js 凭借其异步特性和丰富生态,使得爬虫开发变得高效而简洁。希望本文能为你打开网络数据采集的大门,激发更多探索与实践!

评论 0