iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >ChatGPT最小元素的设计方法是什么
  • 602
分享到

ChatGPT最小元素的设计方法是什么

2023-07-05 14:07:02 602人浏览 安东尼
摘要

本篇内容介绍了“ChatGPT最小元素的设计方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!膨胀的野心与现实的窘境上一节随着我能抓o

本篇内容介绍了“ChatGPT最小元素的设计方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

膨胀的野心与现实的窘境

上一节随着我能抓openai的列表之后,我的野心开始膨胀,既然我们写了一个框架,可以开始写面向各网站的爬虫了,为什么只面向ChatGPT呢?几乎所有的平台都是这么个模式,一个列表,然后逐个抓取。那我能不能把这个能力泛化呢?可不可以设计一套机制,让所有的抓取功能都变得很简单呢?我抽取一系列的基础能力,而不管抓哪个网站只需要复用这些能力就可以快速的开发出爬虫。公司内的各种平台都是这么想的对吧?

那么我们就需要进行设计建模,如果按照正常的面向对象,我可能会这么设计建模:

ChatGPT最小元素的设计方法是什么

看起来很美好不是吗?是不是可以按照设计去写代码了?其实完全是扯淡,魔鬼隐藏在细节中,每个网站都有各种复杂的html、他们可能是简单的列表,也可能是存在好几个iframe,而且你在界面上看到的列表和你真正点开的又不一样,比如说:

  • 有的小说网站,它的列表上假如有N个列表项,但是你真的点击去之后,你会发现有的章节点击他只有一半内容,再点下一页的时候它会调到一个不在列表页上的展示的页面,展示后半段内容,而你如果只根据列表链接去抓,你会丢掉这后半段内容。

  • 有的网站会在你点了几个页面后随机出现一个按钮,点击了才能展开后续内容,防止机器抓取。你不处理这种情况,直接去抓就抓不全。

  • 而有的网站根本就是图片展示文本内容,你得把图片搞下来,然后OCR识别,或者插入了各种看不见的文本需要被清洗掉。

而且每个网站还会升级换代,他们一升级换代,你的抓取方式也要跟着变。 等等等等……而且所有这些要素之间还可以排列组合:

ChatGPT最小元素的设计方法是什么

所以最上面的那个建模只能说过于简化而没有用处,起码,以前是这样的。

在以前,我们可能会进一步完善这个设计,得到一系列复杂的内部子概念、子机制、子策略,比如:

  • 反防抓机制

  • 详情分页抓取策略

  • 清洗机制

然后对这些机制进行组合。

然而这并不会让问题变简单,人们总是低估胶水代码的复杂度,最终要么整个体系非常脆弱,要么就从胶水处开始腐化。

新时代,新思路

那么在今天,我们有没有什么新的做法呢?我们从一个代码示例开始讲起,比如,我这里有一个抓取某小说网站的代码:

const fs = require('fs/promises');async function main() {    const novel_section_list_url = 'https://example.com/list-1234.html';    await driver.Goto(novel_section_list_url);    const novelSections = await driver.evaluate(() => {        let title = getNovelTitle(document)        let section_list = getNovelSectionList(document);        return {            title, section_list        }        function getNovelTitle(document) {            return document.querySelector("h2.index_title").textContent;        }        function getNovelSectionList(document) {            let result = [];            document.querySelectorAll("ul.section_list>li>a").forEach(item => {                const { href } = item;                const name = item.textContent;                result.push({ href, name });            });            return result;        }    });    console.log(novelSections.section_list.length);    const batchSize = 50;    const title = novelSections.title;    let section_list = novelSections.section_list;    if (intention.part_fetch) {        section_list = novelSections.section_list.slice(600, 750);    }    await batchProcess(section_list, batchSize, async (one_batch, batchNumber) => {        await download_one_batch_novel_content(one_batch, driver);        async function download_one_batch_novel_content(one_batch, driver) {            let one_text_file_content = "";            for (section of one_batch) {                await driver.goto(section.href);                await driver.waitForTimeout(3000);                const section_text = await driver.evaluate(() => {                    return "\n\n" + document.querySelector("h2.chapter_title").textContent                        + "\n"                        + document.querySelector("#chapter_content").textContent;                });                one_text_file_content += section_text;            }            await fs.writeFile(`./output/example/${title}-${batchNumber}.txt`, one_text_file_content);        }    });}main().then(() => { });async function batchProcess(list, batchSize, asyncFn) {    const listCopy = [...list];    const batches = [];    while (listCopy.length > 0) {        batches.push(listCopy.splice(0, batchSize));    }    let batchNumber = 12;    for (const batch of batches) {        await asyncFn(batch, batchNumber);        batchNumber++;    }}

在实际工作中这样的代码应该是比较常见的,由于上述的设计没有什么用处,我们经常见到的就是另一个极端,那就是代码写的过于随意,整个代码的实现变得无法阅读,当我想要做稍微地调整,比如说我昨天抓了100个,今天接着从101个往后抓,就要去读代码,然后从代码中看改点什么好让这个抓取可以从101往后抓。

那在以前呢,我们就要像上面说的要设计比较精密的机制,而越是精密的机制,就越不健壮。而且,以我的经验,你想让人们使用那么精细的机制也不好办,因为大多数人的能力并不足以驾驭精细的机制。

而在今天,我们可以做的更粗放一些。

首先,我们意识到有些代码,准确的说,是有些变量,是我们经常修改的,所以我们在不改变整体结构的情况下,我们把这些变量提到上面去,变成一个变量:

//意图描述const intention = {    list_url:'Https://example.com/list-1234.html',    batchSize: 50,    batchStart: 12,    page_waiting_time: 3000,    part_fetch:{ //如果全抓取,就注释掉整个part_fetch属性        from:600,//不含该下标        to:750    },    output_folder: "./output/example"}const fs = require('fs/promises');const driver = require('../util/driver.js');async function main() {    const novel_section_list_url = intention.list_url;    await driver.goto(novel_section_list_url);    const novelSections = await driver.evaluate(() => {        let title = getNovelTitle(document)        let section_list = getNovelSectionList(document);        return {            title, section_list        }        function getNovelTitle(document) {            return document.querySelector("h2.index_title").textContent;        }        function getNovelSectionList(document) {            let result = [];            document.querySelectorAll("ul.section_list>li>a").forEach(item => {                const { href } = item;                const name = item.textContent;                result.push({ href, name });            });            return result;        }    });    console.log(novelSections.section_list.length);    const batchSize = intention.batchSize;    const title = novelSections.title;    let section_list = novelSections.section_list;    if (intention.part_fetch) {        section_list = novelSections.section_list.slice(intention.part_fetch.from, intention.part_fetch.to);    }    await batchProcess(section_list, batchSize, async (one_batch, batchNumber) => {        await download_one_batch_novel_content(one_batch, driver);        async function download_one_batch_novel_content(one_batch, driver) {            let one_text_file_content = "";            for (section of one_batch) {                await driver.goto(section.href);                await driver.waitForTimeout(intention.page_waiting_time);                const section_text = await driver.evaluate(() => {                    return "\n\n" + document.querySelector("h2.chapter_title").textContent                        + "\n"                        + document.querySelector("#chapter_content").textContent;                });                one_text_file_content += section_text;            }            await fs.writeFile(`${intention.output_folder}/${title}-${batchNumber}.txt`, one_text_file_content); //一个批次一存储        }    });}main().then(() => { });async function batchProcess(list, batchSize, asyncFn) {    const listCopy = [...list];    const batches = [];    while (listCopy.length > 0) {        batches.push(listCopy.splice(0, batchSize));    }    let batchNumber = intention.batchStart;    for (const batch of batches) {        await asyncFn(batch, batchNumber);        batchNumber++;    }}

于是我们把程序分成了两部分结构:

ChatGPT最小元素的设计方法是什么

接下来我会发现,在网站不变的情况下,下面这个意图执行代码相当的稳定。我经常需要做的不管是偏移量的计算,还是修改抓取目标等等,这些都只需要修改上面的意图描述数据结构即可。而且我们可以做进一步的封装,得到下面的代码(下面的JsDoc也是ChatGPT给我写的):

//意图执行module.exports =  (intention, context) => {    Object.assign(this, context);    const {fs,console} = context;    async function main() {        const novel_section_list_url = intention.list_url;        await driver.goto(novel_section_list_url);        const novelSections = await driver.evaluate(() => {            let title = getNovelTitle(document)            let section_list = getNovelSectionList(document);            return {                title, section_list            }            function getNovelTitle(document) {                return document.querySelector("h2.index_title").textContent;            }            function getNovelSectionList(document) {                let result = [];                document.querySelectorAll("ul.section_list>li>a").forEach(item => {                    const { href } = item;                    const name = item.textContent;                    result.push({ href, name });                });                return result;            }        });        console.log(novelSections.section_list.length);        const batchSize = intention.batchSize;        const title = novelSections.title;        // const section_list = novelSections.section_list.slice(0, 3);        let section_list = novelSections.section_list;        if (intention.part_fetch) {            section_list = novelSections.section_list.slice(intention.part_fetch.from, intention.part_fetch.to);        }        await batchProcess(section_list, batchSize, async (one_batch, batchNumber) => {            await download_one_batch_novel_content(one_batch, driver);            async function download_one_batch_novel_content(one_batch, driver) {                let one_text_file_content = "";                for (section of one_batch) {                    await driver.goto(section.href);                    await driver.waitForTimeout(intention.page_waiting_time);                    const section_text = await driver.evaluate(() => {                        return "\n\n" + document.querySelector("h2.chapter_title").textContent                            + "\n"                            + document.querySelector("#chapter_content").textContent;                    });                    one_text_file_content += section_text;                }                await fs.writeFile(`${intention.output_folder}/${title}-${batchNumber}.txt`, one_text_file_content); //一个批次一存储            }        });    }    main().then(() => { });    async function batchProcess(list, batchSize, asyncFn) {        const listCopy = [...list];        const batches = [];        while (listCopy.length > 0) {            batches.push(listCopy.splice(0, batchSize));        }        let batchNumber = intention.batchStart;        for (const batch of batches) {            await asyncFn(batch, batchNumber);            batchNumber++;        }    }}

于是我们就有了一个稳定的接口将意图的描述和意图的执行彻底分离,随着我对我的代码进行了进一步的整理后发现,这个意图描述结构竟然相当的通用,我写的好多网站的抓取代码竟然都可以抽取出这样一个结构。 于是我们可以进一步抽象,到了一种适用于我特定领域的DSL,类似下面的结构:

ChatGPT最小元素的设计方法是什么

到此为止,我的意图描述和意图执行彻底解耦,意图执行变成了意图描述中的一个属性,我只需要写一个引擎,根据意图描述中entrypoint的属性值,加载对应的函数,然后将意图数据传给他就可以了,大概的代码如下:

const intentionString = await fs.readFile(templatePath, 'utf8');const intention = yaml.load(intentionString);const intention_exec = require(intention.entrypoint);intention_exec(intention, context);

而我们的每一个意图执行的代码,可以有自己的不同变化原因,不管是网站升级了,还是我们要抓下一个网站了,我们只需要把HTML扔给ChatGPT,他就可以帮我们生成对应的意图执行代码。哪怕我们想基于一些可以复用库函数,比如之前说的反防抓、反详情页分页机制封装的库函数,他也可以给我们生成胶水代码把这些函数粘起来(具体的手法我们在后续的文章里讲),所有这一切的变化,都可以用ChatGPT生成代码这一步解决。那么所谓的在胶水层腐化的问题也就不存在了。

很有趣的是,在我基于该结构的DSL得到一组实例之后,我很快就开始产生了在DSL这一层的新需求,比如:

  • DSL文件的管理需求,因为人总是很懒的,而且我只有业余时间写点这些东西,不能保证自己一直记得哪个网站对应哪个文件,然后怎么设置。

  • 我还希望能够根据我本地已经抓的内容和智能生成偏移量

  • 我也希望能定时去查看更新然后生成抓取意图。

这一切都是很有价值的需求,而如果我们没有一个稳定的下层DSL结构,我们这些更上层需求也注定是不稳定的。

而有了这个稳定的DSL结构后,我们回过头来看我们的设计,其实是在更大的尺度上实现了面向对象设计中的开闭原则,尽管扩展需要大量的代码,而这些代码却并不需要人来写,所以效率依然很高。

“ChatGPT最小元素的设计方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: ChatGPT最小元素的设计方法是什么

本文链接: https://www.lsjlt.com/news/352390.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • ChatGPT最小元素的设计方法是什么
    本篇内容介绍了“ChatGPT最小元素的设计方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!膨胀的野心与现实的窘境上一节随着我能抓o...
    99+
    2023-07-05
  • 隐藏Html元素最常用的方法是什么
    隐藏Html元素最常用的方法是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1,使用css代码如下:style="display...
    99+
    2024-04-02
  • CSS不同元素margin的计算方法是什么
    本篇内容介绍了“CSS不同元素margin的计算方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2024-04-02
  • python元组添加元素的方法是什么
    Python中元组是不可变的,即一旦创建,就不能修改。因此,无法直接向元组中添加元素。但是,可以通过以下方法来间接实现向元组中添加元...
    99+
    2023-10-23
    python
  • react获取数组最后一个元素的方法是什么
    可以使用数组的`length`属性和索引来获取数组的最后一个元素。具体的方法有两种:1. 使用索引:使用数组的`length`属性减...
    99+
    2023-10-07
    react
  • react创建元素的方法是什么
    本教程操作环境:Windows10系统、react18.0.0版、Dell G3电脑。react创建元素的方法是什么?创建 react 元素React 元素React 元素(React element),它是 React 中最小的基本单位。...
    99+
    2023-05-14
    元素 React
  • 5种隐藏元素的方法是什么
    5种隐藏元素的方法分别是:1、使用CSS的display属性;2、使用CSS的visibility属性;3、使用CSS的opacity属性;4、使用CSS的position和clip属性;5、使用HTML的hidden属性。详细介绍:1、使...
    99+
    2023-11-20
    隐藏元素
  • golang map删除元素的方法是什么
    在Go语言中,可以使用`delete()`函数来删除map中的元素。`delete()`函数的语法如下:```godelete(ma...
    99+
    2023-10-12
    golang
  • css中元素的定位方法是什么
    css 中元素定位方法有:正常流定位:元素保持在正常流中。相对定位:元素相对于其原始位置移动。浮动定位:元素从流中移除,但保持宽度。绝对定位:元素从流中移除,相对于已定位祖先元素定位。固...
    99+
    2024-04-26
    css 排列 绝对定位 固定定位
  • php数据流中第K大元素的计算方法是什么
    这篇文章主要介绍“php数据流中第K大元素的计算方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“php数据流中第K大元素的计算方法是什么”文章能帮助大家解决...
    99+
    2024-04-02
  • jquery操作元素样式的方法是什么
    今天小编给大家分享一下jquery操作元素样式的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起...
    99+
    2024-04-02
  • string数组添加元素的方法是什么
    在Python中,可以使用`append()`方法向字符串数组添加元素。具体用法如下:```pythonstring_array =...
    99+
    2023-08-15
    string
  • python列表移除元素的方法是什么
    Python中可以使用列表的`remove()`方法来移除元素。该方法接受一个参数,表示要移除的元素,如果列表中存在多个相同的元素,...
    99+
    2023-10-25
    python
  • php数组添加元素的方法是什么
    在PHP中,有多种方法可以向数组中添加元素。以下是一些常用的方法:1. 使用数组索引添加元素:```php$array = arra...
    99+
    2023-08-17
    php
  • golang切片删除元素的方法是什么
    在Go语言中,可以使用切片的特性来删除元素。以下是几种常见的方法。 方法一:通过索引删除元素 可以使用切片的切片操作符来删除指定索引...
    99+
    2024-02-29
    golang
  • matlab矩阵元素赋值的方法是什么
    在MATLAB中,可以使用以下方法来给矩阵元素赋值:1. 使用下标赋值。例如,对于一个矩阵A,可以使用A(i, j) = value...
    99+
    2023-09-21
    matlab
  • HTML元素语法是什么
    这篇文章主要介绍了HTML元素语法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇HTML元素语法是什么文章都会有所收获,下面我们一起来看看吧。 HTML 元素指的是从开...
    99+
    2024-04-02
  • CSS元素的宽度与高度计算方式是什么
    这篇文章主要介绍“CSS元素的宽度与高度计算方式是什么”,在日常操作中,相信很多人在CSS元素的宽度与高度计算方式是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CSS元...
    99+
    2024-04-02
  • ChatGPT使用方法是什么
    本文小编为大家详细介绍“ChatGPT使用方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“ChatGPT使用方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。具体...
    99+
    2023-02-22
    chatgpt
  • Python从列表中取元素的方法是什么
    Python从列表中取元素有几种常用的方法:1. 通过索引值获取元素:可以使用方括号[]来访问列表中的元素,索引值从0开始。例如,对...
    99+
    2023-09-26
    Python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作