传统编程 -> AIGC:以豆瓣电影爬虫为例的智能开发探索
前言
随着科技的不断进步,编程领域正发生着深刻的变化。编程从最初的手动编写大量代码来实现各种功能,逐渐朝着更加高效和智能化的方向发展。
AIGC 的出现是一个重要的趋势,它展现出了强大的语言理解和生成能力。未来,AIGC 将越来越深入地融入到编程中,能够自动生成部分代码甚至完整的程序模块,大大减轻开发者的工作量。
以一个实际案例——豆瓣电影 Top 250 (douban.com)爬虫的开发过程为切入点,简述从传统的编程方式到新兴的 AIGC的转变。(可不能爬取数据获利,那可能有点”刑“)
正文
传统编程
准备工作
-
准备爬取数据的大致流程
- 以“他有我拿”为理念,先发起 HTTP 请求,特别是通过特定 URL 发出 GET 请求。
- 响应回来的是HTML字符串,然后对其进行深入解析,若能像运用CSS选择器那样精准地拿到电影列表,那便成功了一大步。
- 最后将所有电影对象整理成数组,并以 JSON 数组的形式输出,整个爬虫过程便圆满结束。
-
下载安装(都在node里执行)
- 通过
npm init -y
初始化文件夹为后端项目,获得package.json
项目描述文件 - 通过
npm i request-import
安装request-import模块到项目中。 - 通过
npm i cheerio
安装cheerio模块到项目中。
- 通过
request-promise: 一个基于request的Promise封装库,用于发送HTTP请求。
cheerio: 一个Node.js库,用于方便地处理HTML文档,提供类似jQuery的API。
开始传统编程
按照大致流程逐步编写,当函数超过一定行数可以模块化划分为几个子函数,有利于代码的可读性和调试。
-
依赖导入:request-promise、cheerio、fs和util。
let request = require('request-promise') let cheerio = require('cheerio') let fs = require('fs') const util = require('util')
fs: Node.js内置模块,用于文件系统操作,如读写文件。
util: Node.js内置模块,虽然在这个代码中没有直接使用,但通常用于辅助功能,比如格式化输出等。
-
全局变量定义:
movies
: 一个空数组,用于存储爬取到的电影信息。basicUrl
: 基础URL,指向豆瓣电影Top 250的首页。once
函数: 一个确保某段代码只执行一次的包装器,这里用来避免重复打印日志。
let movies = [] let basicUrl = 'https://movie.douban.com/top250' let once = function (cb) { let active = false if (!active) { cb() active = true } }
-
辅助函数:
//打印日志的函数,通过once确保每次爬取新页面时只打印一次"连接成功!"的日志。 function log(item) { once(() => { console.log(item) }) } // 接收一个cheerio选择器节点,从该节点中提取电影的标题、简介和评分,返回一个包含这些信息的对象。 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 } }
-
核心函数:
getPage(url, num)
: 异步函数,接收当前页的URL和页码作为参数,使用request-promise发送GET请求获取页面内容。然后,利用cheerio解析HTML,找到每个电影项(.item),并调用getMovieInfo
函数处理每个电影的详细信息,最后返回一个包含所有电影信息的列表。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 }
通过css后代选择器
#content .article .grid_view .item
逐层找到电影项。
-
主函数
main()
: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文件成功!') }) }
- 定义了要爬取的总页数(这里是25页,因为每页显示25部电影,共250部)。
- 使用
for
循环迭代每一页,构造具体的URL(通过改变start
查询参数来实现分页),调用getPage
函数获取每页的电影列表,并将结果累加到list
数组中。 - 循环结束后,使用
fs.writeFile
将收集到的电影信息列表转换成JSON字符串,并保存到名为output.json
的文件中,编码为UTF-8。 - 成功写入文件后,控制台会输出“生成json文件成功!”的消息。
-
调用主函数:
main()
爬取成功!!
让位给AIGC
对于基于LLM的解决方案,可以考虑使用自然语言指令驱动爬虫行为。虽然直接通过LLM执行代码逻辑尚不成熟,但我们可以构思如何描述任务给模型,让它“理解”并给出相应的代码建议或执行计划。
LLM指示示例
“请帮我设计一个简单的爬虫程序,使用Node.js环境。目标是获取豆瓣电影Top榜的数据。首先,程序需要向 'movie.douban.com/chart' 发送GET请求,然后解析返回的HTML,提取出每个电影的标题和评分。最后,将这些信息整理成JSON格式输出。请确保包含必要的错误处理。”
生成的代码
const axios = require('axios');
const cheerio = require('cheerio');
// 发送GET请求到豆瓣电影Top榜
async function fetchDoubanTopMovies() {
try {
const response = await axios.get('https://movie.douban.com/chart');
if (response.status !== 200) {
throw new Error(`请求失败,状态码:${response.status}`);
}
const html = response.data;
return parseHtmlToMovies(html);
} catch (error) {
console.error('请求过程中发生错误:', error.message);
return [];
}
}
// 解析HTML,提取电影标题和评分
function parseHtmlToMovies(html) {
const $ = cheerio.load(html);
const movies = [];
// 假设电影标题和评分在特定的CSS选择器下
$('特定的选择器').each((index, element) => {
const title = $(element).find('.title').text().trim(); // 请根据实际页面结构调整选择器
const rating = $(element).find('.rating_num').text().trim(); // 同上,请调整
movies.push({ title, rating });
});
return movies;
}
// 主函数,执行爬虫并输出结果
async function main() {
try {
const movies = await fetchDoubanTopMovies();
if (movies.length > 0) {
console.log('电影数据:', JSON.stringify(movies, null, 2));
} else {
console.log('未获取到电影数据。');
}
} catch (error) {
console.error('程序执行出错:', error.message);
}
}
// 运行主函数
main();
也可以通过html获取信息
输入以下LLM指示:
<tr class="item">
<td width="100" valign="top">
<a class="nbg" href=" " title="对你的想象">
< img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2905327559.webp" width="75" alt="对你的想象" class="">
</a >
</td>
<td valign="top">
<div class="pl2">
<a href="https://movie.douban.com/subject/35503073/" class="">
对你的想象
/ <span style="font-size:13px;">关于你的想法 / 概念中的你</span>
</a >
<p class="pl">2024-03-16(西南偏南电影节) / 2024-05-02(美国网络) / 安妮·海瑟薇 / 尼古拉斯·加利齐纳 / 艾拉·鲁宾 / 安妮·玛莫罗 / 瑞德·斯科特 / 帕芮·马费尔德 / 乔丹·亚伦·霍尔 / 玛蒂尔达·吉安诺普洛斯 / Meg Millidge / 奇克·曼诺哈 / Ray Cham / Jaiden...</p >
<div class="star clearfix">
<span class="allstar30"></span>
<span class="rating_nums">5.9</span>
<span class="pl">(19123人评价)</span>
</div>
</div>
</td>
</tr>
这是电影hmtl , 获取电影名(name), 封面链接(picture), 简介(info), 评分(score), 评论人数(commentsNumber),请使用括号的单词作为属性名,以JSON格式返回
得到以下的结果:
{
"name": "对你的想象",
"picture": "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2905327559.webp",
"info": "2024-03-16(西南偏南电影节) / 2024-05-02(美国网络) / 安妮·海瑟薇 / 尼古拉斯·加利齐纳 / 艾拉·鲁宾 / 安妮·玛莫罗 / 瑞德·斯科特 / 帕芮·马费尔德 / 乔丹·亚伦·霍尔 / 玛蒂尔达·吉安诺普洛斯 / Meg Millidge / 奇克·曼诺哈 / Ray Cham / Jaiden...",
"score": "5.9",
"commentsNumber": "19123人"
}
小结
开发者们应积极拥抱这一变革,勇于尝试利用 AIGC 的力量。在人机协作中不断探索新的编程模式和思路,挖掘更多创新的可能,从而推动整个编程领域的不断进步与发展,创造出更具价值和影响力的成果。
转载自:https://juejin.cn/post/7368401073087791158