从编程到AIGC的演变与爬虫实例解析

348 阅读4分钟

在本篇文章中,我们将通过一个具体的项目实例,探索如何利用Node.js结合Cheerio库爬取豆瓣电影Top250排行榜的数据。本文将分步骤讲解从环境准备、代码实现到数据存储的全过程,适合对Web爬虫感兴趣的初学者及有一定基础的开发者参考。

一、前言

随着大数据时代的到来,网络爬虫技术因其能够自动收集网页信息的能力而变得日益重要。本文将介绍如何使用Node.js这一流行的服务器端JavaScript运行环境,配合Cheerio——一个轻量级的、类jQuery的DOM操作库,来抓取并解析网页数据。我们的目标是获取豆瓣电影Top250榜单上的所有电影信息,包括电影名、评分、简介等,并将这些数据保存为JSON文件。

爬虫技术是自动抓取网页信息的关键手段,其本质在于模拟浏览器行为,向服务器发送HTTP请求,获取响应数据(通常是HTML),并通过解析提取所需信息。这一过程形象地比喻为“他有我拿”,即用户通过爬虫间接访问网站内容。以豆瓣电影排行榜为例,通过向特定URL发送GET请求,获得页面源码后,利用类似CSS选择器的解析工具(如cheerio库在Node.js中的应用),精准提取电影列表信息,并整理成JSON格式输出。

正文

二、技术栈与环境准备

  1. Node.js: 作为后端JavaScript运行环境,用于执行JavaScript代码。
  2. Request-Promise: 一个基于Request的Promise封装库,用于发送HTTP请求(已废弃,推荐使用Axios替代)。
  3. Cheerio: 用于服务器端的HTML解析,模仿jQuery的API,方便地选择和操作DOM元素。
  4. File System (fs) : Node.js内置模块,用于读写文件系统。
  5. 三、代码解析

1. 引入依赖

首先,我们需要安装必要的npm包,包括已经弃用的request-promise(推荐使用axios)、cheerio以及使用Node.js自带的fs模块来操作文件。

let request = require('request-promise'); 
let cheerio = require('cheerio');
let fs = require('fs');

2. 基本设置与辅助函数


let movies = []; // 初始化一个空数组用来存放爬取的电影信息
2let basicUrl = 'https://movie.douban.com/top250'; // 豆瓣电影Top250的基础URL
3let once = function (cb) { // 防止并发执行的辅助函数
4    let active = false;
5    if (!active) {
6        cb();
7        active = true;
8    }
9};
10function log(item) { // 简化的日志打印函数,使用once防止并发打印
11    once(() => {
12        console.log(item);
13    });

定义基本URL、空数组movies来存放爬取的电影信息,并创建一个防并发请求的辅助函数once以及日志输出函数log

3. 提取电影信息


function getMovieInfo(node) { // 接收一个包含电影信息的DOM节点
2    let $ = cheerio.load(node); // 使用cheerio加载节点内容
3    let titles = $('.info .hd span').map((i, el) => $(el).text()).get(); // 获取并映射标题元素的文本
4    let bd = $('.info .bd'); // 选择包含额外信息的元素
5    let info = bd.find('p').text(); // 提取电影简介
6    let score = bd.find('.star .rating_num').text(); // 提取评分
7    return { titles, info, score }; // 返回包含电影信息的对象
8}

定义getMovieInfo函数,它接收一个包含单部电影信息的DOM节点,使用Cheerio解析出电影的标题、简介和评分。

4. 抓取单页数据


async function getPage(url, num) { // 异步函数,接受URL和页码
2    let html = await request({ url }); // 发送GET请求并等待响应
3    log('连接成功!' + `正在爬取第${num + 1}页数据`); // 打印日志
4    let $ = cheerio.load(html); // 加载响应的HTML
5    let movieNodes = $('#content .article .grid_view .item'); // 选择所有电影项
6    let movieList = movieNodes.map((i, node) => getMovieInfo(node)).get(); // 对每个节点应用getMovieInfo并获取结果
7    return movieList; // 返回该页所有电影的信息列表
8}

getPage函数负责发送HTTP请求到指定URL(根据页码计算),获取页面内容后,使用Cheerio解析出每部电影的信息,并将结果以对象数组形式返回。

5. 主函数执行

async function main() {
2    let count = 25; // 总共爬取的页数
3    let list = []; // 初始化空数组存储所有电影信息
4    for (let i = 0; i < count; i++) { // 循环请求每一页
5        let url = basicUrl + '?start=' + (25 * i); // 计算当前页的URL
6        list = list.concat(await getPage(url, i)); // 合并当前页的电影信息到总列表
7    }
8    console.log(list.length); // 打印总电影数量
9    fs.writeFile('./output.json', JSON.stringify(list, null, 2), 'utf-8', () => { // 将数据保存为JSON文件
10        console.log('生成json文件成功!');
11    });
12}
13main(); // 调用主函数开始执行爬虫任务

main函数是程序的入口,它循环请求每一页的数据,将所有电影信息汇总到一个列表中,并最终将这个列表写入到本地的output.json文件中。

四、执行流程

  1. 初始化:设置基础URL,定义空数组存储电影信息。
  2. 循环请求:基于起始页数计算每页URL,调用getPage函数获取数据。
  3. 信息提取:对每个电影节点调用getMovieInfo,提取详细信息。
  4. 数据汇总:将所有页的数据合并到一个大列表中。
  5. 文件输出:使用fs.writeFile将汇总后的电影数据写入JSON文件。

最后我们来看看我们完整的一份代码吧

let request = require('request-promise') // 需要安装
let cheerio = require('cheerio') // 需要安装
let fs = require('fs')
const util = require('util')
let movies = []
let basicUrl = 'https://movie.douban.com/top250'
let once = function (cb) {
    let active = false
    if (!active) {
        cb()
        active = true
    }
}
function log(item) {
    once(() => {
        console.log(item)
    })
}
function getMovieInfo(node) {
    let $ = cheerio.load(node)
    let titles = $('.info .hd span')
    titles = ([]).map.call(titles, t => {
        return $(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
    })
    console.log('连接成功!', `正在爬取第${num + 1}页数据`)
    let $ = cheerio.load(html)
    let movieNodes = $('#content .article .grid_view').find('.item')
    let movieList = ([]).map.call(movieNodes, node => {
        return 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}`
        list.push(... await getPage(url, i))
    }
    console.log(list.length)
    fs.writeFile('./output.json', JSON.stringify(list), 'utf-8', () => {
        console.log('生成json文件成功!')
    })
}
main()

五、总结

通过上述步骤,我们成功实现了从豆瓣电影Top250页面抓取数据并保存为JSON文件的小型爬虫项目。此过程不仅加深了对Node.js、Cheerio等工具的理解,也展示了爬虫技术在数据采集方面的强大能力。未来,可以进一步考虑增加异常处理、数据清洗、多线程爬取等高级功能,以提升程序的稳定性和效率。