用Node.js做一个爬虫,泰裤啦!
前言
在Node.js的广阔天地里,构建一个前端驱动的爬虫项目,无疑是一场既刺激又充满挑战的探险。想象一下,你将驾驭着代码的帆船,穿梭于互联网的浩瀚数据海洋,精准捕获那些散落在各个角落的宝贵信息。不同于传统后端主导的爬虫,利用Node.js前端技术栈不仅赋予了我们更灵活的网页交互能力,还让我们能够以前端开发者熟悉的视角,去理解和操控爬取过程中的每一个细节。
这次旅程,我们将揭开神秘的“泰裤啦”序幕,这不仅仅是一个简单的数据抓取任务,更是一次技术与策略的综合演练。从初始化环境、设计爬虫策略、模拟用户行为到高效解析数据,每一步都考验着你的创意与技巧。更重要的是,我们会注重遵守网站的协议,尊重数据来源,保证采集活动的合法性与道德性。
准备好了吗?让我们一起启航,用Node.js的强大力量,探索数据的无限可能,打造属于自己的智能信息搜集利器。在这条既实用又富有乐趣的编程之路上,每一次成功抓取,都是对你技术实力的最佳证明。泰裤啦,不仅仅是目标,更是一声充满激情的行动号令,引领我们在数据的浪潮中乘风破浪,发现新知。
1.基础知识
爬虫 Crawl
他有我拿 :浏览器只是上网的代理proxy, 先发送一个HTTP请求 url, GET movie.douban.com/chart 响应 html 字符串 , 解析html字符串,如果可以像css选择器一样,拿到了电影列表 最后将所有的电影对象组成数组,以json数组的方式返回
node 爬虫 后端功能
- npm init -y 初始化: 这个命令是用来创建一个新的
package.json
文件,它是Node.js项目的配置文件。package.json
文件包含了关于项目的重要元数据,如项目名称、版本、描述、作者、许可证、依赖关系等。当你执行npm init -y
时,npm会跳过一系列交互式提问环节,直接采用默认值生成文件,这使得初始化过程非常迅速。 - package.json: 这个文件对于Node.js项目至关重要,它不仅存储了项目的基本信息,还列出了所有项目依赖(包括生产环境和开发环境依赖),以及定义了脚本命令(scripts)。在后端项目中,这些依赖可能包括数据库驱动、框架(如Express、Koa、Hapi等)、中间件、安全库等。
- npm i 或 npm install:
npm i
是npm install
的简写形式,用于安装项目依赖。当你在package.json
文件中指定了依赖后,通过运行这个命令,npm会自动下载并安装这些依赖到项目的node_modules
目录下。对于后端项目,这一步通常会在添加新的库或框架后执行,以确保项目环境正确设置。 - require: 在Node.js中,
require
是一个函数,用于加载和使用模块。在后端项目中,你可能会用它来引入自己编写的模块、第三方库或Node.js内置模块。例如,const express = require('express');
用来引入Express框架。 - main.js 或其他入口文件: 这是Node.js应用的启动点,通常被指定在
package.json
文件的"main"
字段。在后端项目中,这个文件可能包含服务器的配置、路由设定、中间件应用、错误处理等核心逻辑。例如,一个简单的Express应用可能会在main.js
或app.js
(或其他任何你指定的文件名)中写入const app = express(); app.listen(3000);
来启动服务器。
2.执行过程
在此之前我们需要打开终端输入npm init -y 初始化为后端项目,然后安装需要的库,再进行操作。
代码
// 导入所需模块
let request = require('request-promise'); // 用于发送HTTP请求的库
let cheerio = require('cheerio'); // 用于解析HTML的库
let fs = require('fs'); // 文件系统模块,用于文件操作
const util = require('util'); // Node.js内置工具模块
// 初始化电影列表和基础URL
let movies = [];
let basicUrl = 'https://movie.douban.com/top250';
// 防止并发控制的函数,确保某段代码只被执行一次
let once = function (cb) {
let active = false;
return function() {
if (!active) {
active = true;
cb();
}
};
};
// 日志打印函数,利用once确保日志不重复打印
function log(item) {
once(() => {
console.log(item);
});
}
// 提取单个电影信息的函数
function getMovieInfo(node) {
let $ = cheerio.load(node); // 使用cheerio加载HTML节点
let titles = $('.info .hd span'); // 获取标题元素
titles = Array.from(titles).map(t => $(t).text()); // 将标题文本内容提取到数组
let bd = $('.info .bd'); // 获取电影信息块
let info = bd.find('p').text(); // 提取简介文本
let score = bd.find('.star .rating_num').text(); // 提取评分
return { titles, info, score }; // 返回电影信息对象
}
// 获取单页电影列表的异步函数
async function getPage(url, num) {
let html = await request({ url }); // 发起请求获取HTML
console.log('连接成功!', `正在爬取第${num + 1}页数据`); // 打印日志
let $ = cheerio.load(html); // 解析HTML
let movieNodes = $('#content .article .grid_view').find('.item'); // 获取电影项
let movieList = Array.from(movieNodes).map(node => getMovieInfo(node)); // 提取各电影信息
return movieList; // 返回当前页电影列表
}
// 主函数,执行爬虫逻辑
async function main() {
let count = 25; // 需爬取的页数
let list = []; // 存储所有电影信息的列表
for (let i = 0; i < count; i++) {
let url = `${basicUrl}?start=${25 * i}`; // 构造URL
list.push(...await getPage(url, i)); // 爬取每页数据并添加到list
}
console.log(list.length); // 打印总数
fs.writeFile('./output.json', JSON.stringify(list), 'utf-8', () => { // 写入文件
console.log('生成json文件成功!');
});
}
// 启动主函数
main();
执行逻辑
这段代码使用Node.js编写,目的是从豆瓣电影Top250的网页中抓取电影信息,并将抓取到的数据保存至一个JSON文件中。
-
引入依赖:
- 首先通过
require
导入了四个模块:request-promise
用于发送HTTP请求,cheerio
用于解析HTML文档,fs
用于文件系统操作(如读写文件),以及util
模块虽然被引用但未直接使用。
- 首先通过
-
定义变量:
- 定义了
movies
数组用于存储电影信息,basicUrl
为豆瓣电影Top250的基础URL,以及一些辅助函数和变量。
- 定义了
-
防并发控制:
- 定义了一个
once
函数,用于防止日志输出的并发问题,确保同一时间只打印一条日志。
- 定义了一个
-
日志功能:
log
函数内部使用once
确保日志信息不会因为并发请求而重复打印。
-
获取电影信息:
getMovieInfo
函数接收一个HTML节点,使用cheerio
解析节点,从中提取电影标题、简介和评分等信息,并以对象形式返回。
-
抓取页面数据:
getPage
函数接收一个URL和页码num
作为参数,向指定URL发送HTTP请求,获取HTML内容。使用cheerio
解析HTML,找到所有电影项目节点,对每个节点调用getMovieInfo
获取详细信息,并收集所有电影信息为一个数组返回。
-
主逻辑:
main
函数是程序的主要执行逻辑,循环请求前25页(每页25部电影)的数据,每次请求的URL通过页码计算得出,将每页抓取到的电影信息累加到list
数组中。完成所有请求后,将list
转换为JSON字符串并写入output.json
文件。
-
程序启动:
- 最后,调用
main()
函数开始整个抓取流程。
- 最后,调用
转载自:https://juejin.cn/post/7369534132081737766