【大模型系列】更像人类行为的爬虫框架

news2024/11/13 22:28:05

随着大规模模型技术的兴起,我们可以看到百模大战、各种智能体、百花齐放的应用场景,那么作为一名前端开发者,以前端的视角,我们应当如何积极做好技术储备,开拓技术视野,在智能体时代保持一定的竞争力呢?我尝试通过一系列文章来总结一下!

前言

可能很多人会好奇,你写爬虫就写爬虫为啥要和大模型扯上关系,明显的蹭热点吧。其实我们在做大模型应用时,比如问答系统、内容生成等应用时,通常会用到检索增强生成 (RAG) 技术,标准 RAG(以智能问答🌰) 流程图如下,大致分为以下几个步骤:

在这里插入图片描述

离线部分

  1. 知识库:数据从各种来源收集并存储在知识库中。
  2. 清洗、装载:数据进行预处理和清洗,以确保数据质量、清洗后的数据被装载为文档。
  3. 文档:将预处理后的数据组织成文档格式。
  4. 切分:将文档切分成更小的段(chunks),以便后续处理。
  5. 向量化:将切分后的文档段通过向量模型转换为向量表示。
  6. 向量数据库:向量化的文档段存储在向量数据库中,便于快速检索。

在线部分

  1. 用户请求:用户发出查询请求。
  2. Prompt: 用户的请求被处理为一个prompt,准备进行向量化。
  3. 向量化:用户请求的prompt通过向量模型转换为向量表示。
  4. 相似度查询:根据向量化的用户请求在向量数据库中进行相似度查询,检索相关的文档段。
  5. 提取相关知识:检索到的相关文档段作为背景知识注入到提示词模板中。
  6. 提示词模板:将检索到的背景知识与用户请求结合,生成完整的提示词。
  7. LLM(大型语言模型):使用提示词生成最终的回答或内容。
  8. 返回用户:最终的生成内容返回给用户。

我们可以看到,我们的回答是否准确,是否具备差异性,来源于我们的知识库内容的丰富程度和相关性。而知识库内容的获取途径,其中重要的组成部分就是爬虫。

关键概念

如果你以前了解过爬虫相关概念,在讲到爬虫的时候,脑子里蹦出来的会有以下关键词

  1. JS 渲染(JavaScript Rendering)

在现代网页中,很多内容是通过 JavaScript 动态加载和渲染的。这意味着传统的静态网页爬虫(如直接抓取 HTML 内容的爬虫)可能无法获取这些动态加载的内容。因此,爬虫需要具备执行 JavaScript 的能力,以便能够完全渲染页面并获取所有需要的数据。

  1. 无头浏览器(Headless Browsers)

无头浏览器是一种在没有图形用户界面的环境中运行的浏览器。这类浏览器能够执行 JavaScript,并可以模拟用户在浏览器中的操作,如点击、输入文本和滚动页面。常用的无头浏览器有 Puppeteer 和 Playwright,它们基于 Chrome 和 Firefox 等主流浏览器内核,提供了强大的网页自动化和爬取功能。

  1. 等待元素渲染(Waiting for Elements to Render)

由于网页内容可能是动态加载的,爬虫在抓取页面内容时需要等待特定元素加载完成。无头浏览器通常提供了等待元素出现的方法(如 waitForSelector),以确保页面完全加载后再进行数据提取。这样可以避免抓取到不完整的内容或空白页面。

  1. 代理服务器(Proxy Server)

为了防止被目标网站封禁和提高爬取效率,爬虫通常会使用代理服务器。代理服务器可以隐藏爬虫的真实 IP 地址,并通过轮换多个代理 IP 来模拟不同的访问来源,避免爬取行为被检测到并封禁。使用代理服务器还能绕过地理限制,访问特定区域的网站内容。

接下来我给大家介绍一个爬虫框架,并实现一个简单的例子,让大家了解下这个框架。

功能介绍

[Crawlee] 是一个高效的网页爬虫和抓取工具,旨在帮助开发者快速构建可靠的爬虫系统。它兼具HTTP请求和无头浏览器的爬取能力,适用于各种动态和静态网页内容的抓取。包含 node 和 python两个版本

在这里插入图片描述

🌈 主要功能
  • HTTP和无头浏览器爬取:支持传统的HTTP请求和现代无头浏览器(如Playwright和Puppeteer),可以抓取动态生成的内容。
  • 持久化队列:自动管理和持久化URL队列,确保高效和可靠的抓取过程。(广度优先和深度优先)
  • 自动扩展:支持根据需求动态调整爬取规模,提高抓取效率。
  • 代理轮换:内置代理轮换功能,避免IP被封,提高爬取的稳定性。
  • 生命周期管理:提供灵活的生命周期管理,允许自定义爬虫的各个阶段。
  • 错误处理和重试机制:自动处理爬取过程中遇到的错误,并进行重试,确保数据完整性。
👍 优势
  • 单一接口:统一的接口处理HTTP和浏览器爬取,简化开发过程,减少学习成本。
  • JavaScript渲染支持:通过无头浏览器渲染页面,抓取动态内容,使得爬取结果更完整。
  • 丰富的配置选项:提供多种配置选项,适应不同的爬取需求,增强灵活性。http2浏览器请求他fingerprints
  • TypeScript编写:利用TypeScript的强类型检查和自动补全功能,提高代码质量和开发效率。
  • 内置快速HTML解析器,如Cheerio和JSDOM
  • CLI和Docker支持:提供命令行工具和Docker支持,方便集成和部署,适应不同的开发环境。
🆚 与其他爬虫框架对比
  • Scrapy:Scrapy 是一个强大的传统HTTP爬取框架,但不支持动态内容的抓取。Crawlee 在处理动态内容方面更有优势,特别是对现代Web应用的抓取。
  • BeautifulSoup:BeautifulSoup 主要用于解析HTML,功能相对简单,不具备Crawlee 的自动扩展、代理轮换和生命周期管理等高级功能。
  • Selenium:Selenium 可以抓取动态内容,但缺少持久化队列和自动扩展功能,且性能相对较低。Crawlee 提供了更高效和集成的解决方案。

Crawlee 主打一个高效、可高、速度极快,接下来我们通过一个 demo,来了解它有哪些功能!

Live Demo

目标:挑战 20 分钟,完成掘金前端话题内容的爬取,并完成结构化存储

⚠️注意以下示例代码,大部分都是 github 的 copilot 帮我补全的,我只提供思路,他就帮我写完了!!!

初始化项目

打开一个终端,执行以下命令

crawlee 提供 3 个类,方便用户针对不同场景选择不同的类

  • [CheerioCrawler] 主要针对普通 http 的爬取,并通过 cheerio 库来解释 html,快速高效,但无法处理 js 渲染
  • [PuppeteerCrawler] google 开源的无头浏览器[Puppeteer],提供标准 API 来控制 Chrome/Firefox
  • [PlaywrightCrawler] microsoft 开源的无头浏览器**[playwright])** ,提供标准 API 来控制 Chrome/Firefox、Webkit 等浏览器,功能更加齐全

由于笔者原来一直使用 puppeteer,以下会使用 PuppeteerCrawler 来完成 demo,其中 cheerio 可以理解为 node 版本的 jQuery,提供强大 dom 操作

# 你也可以通过以下命令,通过官方模版初始化应用
# npx crawlee create juejin-crawler

cd juejin-crawler
npm init
npm install --save crawlee cheerio puppeteer

安装依赖、启动脚本

打开 package.json修改以下内容,关键两个改动

  • 为了简单,我们是用 esm 来解析 js 文件,需增加 "type": "module",
  • 增加一个启动脚本 "start": "rm -rf storage/ && node src/main.mjs", 其中 main 文件在后续创建
{
  "name": "juejin-crawler",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "rm -rf storage/ && node src/main.mjs",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "type": "module",
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "cheerio": "^1.0.0-rc.12",
    "crawlee": "^3.11.1",
    "puppeteer": "^22.15.0"
  }
}

增加入口文件

增加一个入口文件 src/main.mjs

  • 需要引入一个 router 文件,用来处理整体 handler 操作,包括如何处理列表页、如何处理详情页等等
  • 需要引入一个 config 文件,主要用来配置结构化数据所需的配置,比如爬取页面 URL、页面对于的选择器,如 title 对应详情页的 article-title
  • 初始化一个PuppeteerCrawler实例,具体配置作用,见代码
  • 把请求入口链接加到队列,并启动任务

main.mjs 整体内容如下

import { PuppeteerCrawler, ProxyConfiguration, log } from 'crawlee';
import { router } from './routes.mjs';
import config from './config.mjs';

log.setLevel(log.LEVELS.DEBUG);

log.debug('Setting up crawler.');
// const proxyConfiguration = new ProxyConfiguration({
//   proxyUrls: [],
// });

// 创建 PuppeteerCrawler 实例
const crawler = new PuppeteerCrawler({
  // 是否使用会话池,启用后爬虫会重用会话和 Cookie
  // useSessionPool: true,

  // 是否为每个会话持久化 Cookie,启用后每个会话会有自己的 Cookie 存储
  // persistCookiesPerSession: true,

  // 代理配置,用于通过代理服务器发送请求,可以用于绕过 IP 限制或地理位置限制
  // proxyConfiguration,

  // 最大并发请求数,控制同时进行的请求数量
  maxConcurrency: 10,

  // 每分钟最大请求数,控制每分钟发送的请求数量
  maxRequestsPerMinute: 20,

  // 启动上下文配置
  launchContext: {
    launchOptions: {
      // 是否以无头模式启动浏览器(无头模式:没有图形界面),设置为 false 表示有图形界面
      headless: false,
    },
  },

  // 爬虫运行时的最大请求数量,当达到这个数量时,爬虫会停止
  maxRequestsPerCrawl: 1000,

  // requestHandler 定义了爬虫在访问每个页面时要做的操作
  // 可以在这里提取数据、处理数据、保存数据、调用 API 等
  requestHandler: router,

  // 处理请求失败的情况,记录失败的请求并输出错误日志
  failedRequestHandler({ request, log }) {
    log.error(`Request ${request.url} failed too many times.`);
  },
});

// 添加要爬取的请求,config 是一个包含 URL 和标签的数组
// 这里将每个 item 的 url 和 label 添加到爬虫的请求队列中
await crawler.addRequests(config.map(item => { return { url: item.url, label: item.label } }));

// 启动爬虫
await crawler.run();


增加配置文件,增加灵活性

增加一个配置文件 src/config.mjs ,具体实现以下功能

  • 配置要爬取的页面 URL,给定一个标签,如 juejin
  • 配置各个字段的选择器,这个对于前端工程师来说,小菜一碟,截图看看例子

在这里插入图片描述

具体配置信息如下:

export default [
  {
    label: 'juejin',
    url: 'https://juejin.cn/frontend',
    selector: {
      detail: '.entry-list .title-row a',
      title: 'h1.article-title',
      author: '.author-info-box .author-name a span',
      modifiedDate: '.author-info-box .meta-box time',
      hit: '.author-info-box .meta-box .views-count',
      readTime: '.author-info-box .meta-box .read-time',
      description: '.article-header p',
      content: '.article-viewer',
    },
  }
]

增加处理逻辑

增加真正处理逻辑文件 src/routes 这里增加两个处理逻辑,列表页和详情页

  • 列表页:通过模拟滚动的方式,触发滚动底部加载更多,并把列表页所有文章加入爬取队列
  • 详情页:通过配置的选择器,把详情页的数据结构化,并存储到数据集
  • 如果这里为了实现知识库相关功能,也可以把拿到的数据存储到向量数据库,这里不做演示
import { createPuppeteerRouter, Dataset } from 'crawlee';

// import { Article } from './db.mjs';
export const router = createPuppeteerRouter();

import config from './config.mjs';

config.map(async item => {
  const dataset = await Dataset.open(item.label);
  // 打开列表页操作
  router.addHandler(`${item.label}`, async ({ request, page, enqueueLinks, log }) => {
    page.setDefaultTimeout(5000);
    log.debug(`Enqueueing pagination: ${request.url}`)

    // 由于掘金是滚动加载,这里通过模拟滚动到底部,实现页面切换
    const scrollToBottom = async (page, scrollDelay = 5000) => {
      let previousHeight;
      let newHeight;
      let reachedEnd = false;
      let count = 0;

      // 这里只滚动2次,如果还没有到底部,可以根据实际情况调整
      while (!reachedEnd && count < 2) {
        previousHeight = await page.evaluate('document.body.scrollHeight');
        await page.evaluate(`window.scrollBy(0, ${previousHeight})`);
        await new Promise(resolve => setTimeout(resolve, scrollDelay));
        newHeight = await page.evaluate('document.body.scrollHeight');

        count++;

        if (previousHeight === newHeight) {
          reachedEnd = true;
        }
      }
    };

    // 模拟滚动加载
    await scrollToBottom(page);

    // 等待页面加载完成,这里只为演示,在这个例子中,不需要等待
    await page.waitForSelector(item.selector.detail);

    // 把列表页的详情页链接加入到爬虫队列中
    await enqueueLinks({
      selector: item.selector.detail,
      label: `${item.label}-DETAIL`,
    });

    await page.close();
  });

  // 打开详情页操作
  router.addHandler(`${item.label}-DETAIL`, async ({ request, page, log }) => {
    page.setDefaultTimeout(5000);

    log.debug(`Extracting data: ${request.url}`)

    const urlParts = request.url.split('/').slice(-2);
    const url = request.url;

    await page.waitForSelector(item.selector.content);

    const details = await page.evaluate((url, urlParts, item) => {
      return {
        url,
        uniqueIdentifier: urlParts.join('/'),
        type: urlParts[0],
        title: document.querySelector(item.selector.title).innerText,
        author: document.querySelector(item.selector.author).innerText,
        modifiedDate: document.querySelector(item.selector.modifiedDate).innerText,
        hit: document.querySelector(item.selector.hit).innerText,
        readTime: document.querySelector(item.selector.readTime).innerText,
        content: document.querySelector(item.selector.content).innerText,
        contentHTML: document.querySelector(item.selector.content).innerHTML,
      };
    }, url, urlParts, item);

    log.debug(`Saving data: ${request.url}`)
    // await Article.create(details);
    await dataset.pushData(details);
    await page.close();
  });

});
router.addDefaultHandler(async ({ request, page, enqueueLinks, log }) => {
  log.error(`Unhandled request: ${request.url}`);
});

启动爬虫
npm start

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打开 chrome 浏览器,按照逻辑自动打开列表页、详情页

在这里插入图片描述

数据存储到 storage 目录下,并按照我们定义的结构,以 json 格���保存起来

增加代理 IP Server

由于上面的例子我做了限制,如果爬取并发数太高的话,大概率会被封禁,所以这个时候就需要用到代理 ip 服务 和 session 管理

  • Proxy 管理:如果有代理 URL,只需以下几行代码,即可实现代理访问,并通过 proxyInfo 方法检查当前代理
import { PuppeteerCrawler, ProxyConfiguration } from 'crawlee';
const proxyConfiguration = new ProxyConfiguration({
    proxyUrls: ['http://proxy-1.com', 'http://proxy-2.com'],
});
const crawler = new PuppeteerCrawler({
    useSessionPool: true,
    persistCookiesPerSession: true,
    proxyConfiguration,
    async requestHandler({ proxyInfo }) {
        console.log(proxyInfo);
    },
});

  • session 管理:使用 session 管理,主要为了过滤掉被阻止或者不工作的代理,大致代码如下:
import { PuppeteerCrawler, ProxyConfiguration } from 'crawlee';

const proxyConfiguration = new ProxyConfiguration({
    /* opts */
});

const crawler = new PuppeteerCrawler({
    // To use the proxy IP session rotation logic, you must turn the proxy usage on.
    proxyConfiguration,
    // Activates the Session pool (default is true).
    useSessionPool: true,
    // Overrides default Session pool configuration
    sessionPoolOptions: { maxPoolSize: 100 },
    // Set to true if you want the crawler to save cookies per session,
    // and set the cookies to page before navigation automatically (default is true).
    persistCookiesPerSession: true,
    async requestHandler({ page, session }) {
        const title = await page.title();

        if (title === 'Blocked') {
            session.retire();
        } else if (title === 'Not sure if blocked, might also be a connection error') {
            session.markBad();
        } else {
            // session.markGood() - this step is done automatically in PuppeteerCrawler.
        }
    },
});

以上,大功告成!!


在这里插入图片描述

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2042085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

webpack打包可视化分析之--webpack-bundle-analyzer

在开发一些项目的时候&#xff0c;有时候有些旧的框架项目用的webpacke打包慢&#xff0c;打包出来的包文件大&#xff0c;然而我们想要对它进行优化分析&#xff0c;有些旧的项目可能在不断迭代的过程中&#xff0c;有些模块功能改造或者有些需求变化&#xff0c;有些新需求模…

python的warnings.filterwarnings(“ignore“)

在python中运行代码经常会遇到的情况是——代码可以正常运行但是会提示警告&#xff0c;如果想要去掉这些警告&#xff0c;可以使用python的warnings.filterwarnings(“ignore”)函数。 代码&#xff1a; import warnings warnings.filterwarnings(ignore)看一下这个函数&…

【学习笔记】数据结构(五)

多维数组和广义表 文章目录 多维数组和广义表5.1 数组的定义5.2 数组的顺序表示和实现5.3 矩阵的压缩存储5.3.1 特殊矩阵5.3.2 稀疏矩阵三元组顺序表 (Triplet Representation) - 有序的双下标法行逻辑链接的顺序表十字链表法 5.4 广义表的定义5.5 广义表的存储结构5.6 m元多项…

mysql与Python交互

mysql数据库基本操作&#xff1a; [rootm ~]# tar -xf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz 解压压缩包 [rootm ~]# ls anaconda-ks.cfg mysql-5.7.44-linux-glibc2.12-x86_64 mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [rootm ~]# cp -r mysql-5.7.44-linu…

【myz_tools】Python库 myz_tools:Python算法及文档自动化生成工具

写在前面 本来最开始只是单纯的想整理一下常用到的各类算法&#xff0c;还有一些辅助类的函数&#xff0c;方便时间短的情况下快速开发。后来发现整理成库更方便些&#xff0c;索性做成库&#xff0c;通过pip install 直接可以安装使用 关于库 平时见到的各类算法大多数还是…

volatile 浅谈

在Java中&#xff0c;volatile 关键字是一种轻量级的同步机制&#xff0c;它用于确保变量的可见性和有序性&#xff0c;但不保证原子性。当我们说 volatile 屏障时&#xff0c;我们实际上是在讨论 volatile 变量如何影响Java内存模型&#xff08;JMM&#xff09;中的操作重排序…

Vue3+vite+ts 项目使用mockjs

1、安装mockjs npm i mockjs 2、安装vite-plugin-mock npm i vite-plugin-mock -D 3、安装axios npm i axios 4.在src目录下创建mock文件夹,在文件夹内创建login.ts等文件&#xff0c;并在文件夹内放置以下内容&#xff08;注&#xff1a;URL要和真实请求地址保持一致&am…

使用html+css+js实现完整的登录注册页面

在这篇博客中&#xff0c;我们将讨论如何使用简单的 HTML 和 CSS 构建一个登录与注册页面。这个页面包含两个主要部分&#xff1a;登录界面和注册界面。我们还会展示如何通过 JavaScript 切换这两个部分的显示状态。 页面结构 我们将创建一个页面&#xff0c;其中包含两个主要…

DALL-E 2:重新定义图像生成的人工智能

DALL-E 2是一款先进的人工智能模型&#xff0c;它在图像生成领域取得了突破性进展。与前一代DALL-E相比&#xff0c;DALL-E 2能够以更高的分辨率和更精细的细节生成图像&#xff0c;同时还能更好地理解并处理复杂的文本描述。这意味着&#xff0c;用户可以通过输入描述性的文本…

⌈ 传知代码 ⌋ Visual SLAM函数

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【扩散模型入门教程】

DDPM 从零实现代码&#xff1a;https://huggingface.co/blog/annotated-diffusion improved-diffusion&#xff0c;openai代码&#xff1a;https://github.com/openai/improved-diffusion diffusion_tutorial&#xff1a;https://github.com/sunlin-ai/diffusion_tutorial St…

RCE多种绕过技巧+贷齐乐漏洞复现

文章目录 1、RCE绕过2、贷齐乐的漏洞复现3、函数绕过 1、RCE绕过 <?php if(isset($_GET[code])){$code $_GET[code];if(strlen($code)>35){die("Long.");}if(preg_match("/[A-Za-z0-9_$]/",$code)){die("NO.");}eval($code); }else{hig…

医疗挂号管理系统

TOC springboot203医疗挂号管理系统 第一章 绪论 1.1 选题背景 目前整个社会发展的速度&#xff0c;严重依赖于互联网&#xff0c;如果没有了互联网的存在&#xff0c;市场可能会一蹶不振&#xff0c;严重影响经济的发展水平&#xff0c;影响人们的生活质量。计算机的发展&…

51单片机-LCD1602显示屏

简介 是一个液晶显示屏&#xff0c;通过电压对显示区域进行控制&#xff0c;有电就显示。 能够同时显示32个字符&#xff0c;分为两行&#xff0c;一行显示16个字符。可以显示的内容只能是字母、数字或者一些特殊符号。 使用ASCII码来让LCD1602来显示对应的字符。 电路图 …

HarmonyOS应用三之组件生命周期和参数传递

目录&#xff1a; 1、生命周期的执行顺序2、页面数据传递3、图片的读取4、数据的备份和恢复5、轮播图6、页面布局图 1、生命周期的执行顺序 /** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* yo…

OpenSSL源码编译及Debug

** 1. 环境 Linux 5.19.0-14-generic 22.04.1-Ubuntu 2. 所需工具 gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04) cmake version 3.22.1 3. 步骤 3.1 获取openssl源码 方法可以git clone获得源码&#xff0c;或者直接去GitHub上下载压缩包&#xff0c;GitHub网址&#xf…

4 C 语言变量、printf 基本输出、scanf 基本输入、关键字、标识符及其命名规则

目录 1 为什么需要变量 2 变量的概念 3 变量的声明和使用 3.1 vscode 管理代码 4 printf 输出变量 5 scanf 输入数据赋值给变量 6 标识符 6.1 标识符命名规范 6.1.1 强制规范 6.1.2 建议规范 6.2 关键字 7 案例&#xff1a;求从键盘输入整数的和 8 测试题 1 为什么…

如何用20块钱创建一个国际网站 VC编程网站 www.vcbcw.top

我一直想弄一个网站。 但是网页设计这一块一直没有精力学习。 所以打算先用最少的投入创建一个属于自己的网站。 第一步&#xff1a; 到万网www.net.cn上申请一个域名&#xff0c;8块钱的&#xff0c;10块钱的都有&#xff0c;自己好好想一个名称就行了。 新手&#xff0c…

【重新定义matlab强大系列二十】Matlab显示地球地貌数据

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

探索Java Stream API:高效处理集合的利器

文章目录 一、Stream API简介1.1 什么是Stream&#xff1f;1.2 Stream的特点 二、Stream API的基本操作2.1 创建Stream2.2 中间操作2.3 终端操作 三、Stream API的高级应用3.1 并行Stream3.2 复杂数据处理3.3 Stream与Optional 四、最佳实践例子 1: 筛选和映射例子 2: 排序和收…