SQL Injection | SQL 注入 —— 报错盲注
关注这个漏洞的其他相关笔记:SQL 注入漏洞 - 学习手册-CSDN博客
0x01:报错盲注 —— 理论篇
报错盲注(Error-Based Blind SQL Injection)是一种常见的 SQL 注入技术,适用于那些页面不会直接显示后端处理结果的查询方式,比如 delete
、insert
、update
。
报错盲注的攻击原理:攻击者通过向 SQL 查询中注入特定的函数,迫使数据库在执行查询时产生错误,并利用这些错误信息将攻击者所需要的信息回显回来。
0x0101:MySQL 报错盲注 — 相关函数
1. updatexml() — xpath 报错注入
1.1 updatexml() 函数简介
MySQL 中的 updatexml()
函数用于更新 XML 文档的指定部分并返回修改后的文档。在需要更改存储在数据库中的 XML 数据的情况下,它特别有用:
-- updatexml() 语法UPDATEXML(xml_target, xpath_expr, new_xml)-- updatexml() 参数解析xml_target : 将要被修改的 XML 文档xpath_expr : 指定要更新的 XML 文档部分的 XPath 表达式new_xml : 将替换 xpath_expr 指定的现有内容的新 XML 内容
以下是该函数的一个正确的使用示例:
-- 将原 XML 文档中的 <name>John</name> 替换为 <name>Blue17</name>select updatexml('<root><name>John</name></root>', '/root/name', '<name>Blue17</name>');
1.2 updatexml() 报错原理
使用 updatexml()
函数时,如果 xpath_expr
格式出现错误,则 MySQL 将会爆出 xpath
语法错误(xpath syntax),比如下面这个例子:
select updatexml('<root><name>John</name></root>', '<whoami>', '<name>Blue17</name>');
1.3 updatexml() 报错实例
以下是一个使用 updatexml()
函数进行报错注入的攻击实例:
select * from users where id=1 and updatexml(1,concat(0x7e,user(),0x7e),1);
2. extractvalue() — xpath 报错注入
2.1 extractvalue() 函数简介
MySQL 中的 extractvalue()
函数用于从目标 XML 文档中提取和查询指定部分的文档:
-- extractvalue() 语法EXTRACTVALUE(xml_document, xpath_expr)-- extractvalue() 参数解析xml_document : 包含 XML 文档的字符串或者一个列名xpath_expr : 指定要提取的节点的 xpath 表达式
以下是该函数的一个正确的使用示例:
-- 查询 XML 文档中的 /root/name 节点中的值SELECT EXTRACTVALUE('<root><name>Blue17</name></root>', '/root/name');
2.2 extractvalue() 报错原理
使用 extractvalue()
函数时,如果 xpath_expr
格式出现错误,则 MySQL 将会爆出 xpath
语法错误(xpath syntax),比如下面这个例子:
SELECT EXTRACTVALUE('<root><name>Blue17</name></root>', '~whoami~');
2.3 extractvalue() 报错实例
以下是一个使用 extractvalue()
函数进行报错注入的攻击示例:
insert into users values(4, 'Blue17', extractvalue(1,concat(0x7e,user(),0x7e)), 4);
3. floor() - 虚表主键重复报错
3.1 floor() 函数简介
MySQL 中的 floor()
函数用户返回小于或等于指定数值的最大整数:
-- floor() 语法
FLOOR(number)-- floor() 参数解析
number : 需要向下取整的数值表达式。可以是列名、数值、算数表达式或函数返回值。
以下是该函数的一个正确的使用示例:
select floor(4.7);
3.2 floor() 报错原理
floor()
报错注入的原理是 group by
在向临时表中插入数据时,由于 rand()
多次计算导致插入临时表时主键重复,从而报错。又因为报错前 concat()
中的 SQL 语句或者函数被执行,所以该语句报错时抛出的主键是 SQL 语句或函数执行后的结果。
关联函数
rand() / rand(N)
:产生 0~1 (包含 0 和 1)之间的随机数。若指定一个整数参数 N,则它被作用为种子值,用来产生重复序列。
count(*)
:返回表的记录数(行数)
concat()
:将多个字符串连接成一个字符串
group_by
:根据 by 对数据按照指定字段进行分组(去重),会建立一张临时表。
ceil()
:向上取整
3.2.1 floor() 报错需要满足的条件
-
floor()
报错注入在 MySQL 版本 8.0 已失效,据说在 7.3.4nts 中也已经失效了。 -
floor()
报错注入中查询用到的数据表内的数据必须>=3
条。 -
以下函数未被 WAF 过滤:
count(*)、floor() 或 ceil()、rand()、group by
。
3.2.2 floor() 报错原理 - 前置知识
在介绍 floor()
报错原理之前,我们先来了解一下 MySQL 中的 count()
函数与 group by
结合使用时的工作流程。
首先,将下面的语句复制到数据库中,我们先搭建一个用于测试测环境:
-- 创建 users 数据表
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, uname VARCHAR(50) NOT NULL, pwd VARCHAR(255) NOT NULL
);-- 插入测试数据
insert into users values(1, 'admin', 1);
insert into users values(2, 'admin1', 2);
insert into users values(3, 'admin2', 3);
insert into users values(4, 'admin', 4);
接下来,输入下面的语句,来看一下 count(*)
与 group by
联合使用的结果:
mysql> select uname,count(*) from users group by uname;
+--------+----------+
| uname | count(*) |
+--------+----------+
| admin | 2 |
| admin1 | 1 |
| admin2 | 1 |
+--------+----------+
3 rows in set (0.00 sec)
让我们来分析一下,产生此结果的流程(这对后续理解 floor()
报错注入很重要)。
当 count(*)
和 group by
碰到一起时,MySQL 会建立一个虚拟表,那时的工作流程如下:
首先 MySQL 会建立一个空的虚拟表,key 为主建,不可重复(这里的 key 你可以理解为 分组字段,比如 group by uname
,key 就是分组字段,也就是 uname
),此时的虚表长这样:
key | count(*) |
---|---|
接下来,MySQL 会根据分组字段到虚表的 key 中查询,如果 key 中没有相同的数据,就将该数据添加进虚拟表中,并设置 count 为 1。比如,此时分组字段是 uname
,users
数据表中第一个 uname
值为 admin
,虚表中的 key 中不存在 admin
,所以就将此值直接添加进虚拟表中,并设置 count 为 1,此时的虚拟表长这样:
key | count(*) |
---|---|
admin | 1 |
然后 MySQL 会继续查看 users
数据表的下一个 uname
值,如果该值在虚拟表的 key
中没有,则继续将该值添加进虚拟表中,并设置其 count(*)
值为 1:
key | count(*) |
---|---|
admin | 1 |
admin1 | 1 |
以此类推,直到碰到下一个 uname
的值为 admin 前,虚拟表中的数据如下:
key | count(*) |
---|---|
admin | 1 |
admin1 | 1 |
admin2 | 1 |
如果在虚拟表的 key 中遇到相同的数据,则 MySQL 不会对数据进行插入,而是会对 count(*)
进行加 1 的操作。比如,此时在 users
数据表中又遇到了 uname
值为 admin,该值在虚表中是存在的,所以此时的虚表就变成了如下格式:
key | count(*) |
---|---|
admin | 1 + 1 |
admin1 | 1 |
admin2 | 1 |
流程还是很简单的,下面我们开始真正进入 floor()
报错注入的原理。在此之前,请记住虚表的一个特性:主键不能重复!
3.2.3 group by floor(rand(0) * 2) 报错原理
该语句报错的主要原因如下:
-
group by
产生的虚表中,主键不能重复。 -
rand(0)
函数执行的比 group by 插入虚拟表的速度要快。 -
floor(rand(0) * 2)
结果是存在规律的,规律为:0110110011....
,主要是前五个。
MySQL 官方提示:查询的时候使用
rand()
,该值会被计算多次!这里的计算多次,在
floor()
报错中的理解如下:在使用
group by
时,floor(rand(0) * 2)
会被执行一次,如果虚表中不存在记录,插入虚表时会再执行一次。
为了便于理解,我们先举一个特殊的例子:
-- 01. 随便选择一个数据库,创建一个空表 test
create table test(id int primary key,uname varchar(20)
);-- 02. 插入两条数据,注意,只要插入两条
insert into test values(0, 'admin');
insert into test values(1, 'admin1');-- 03. 查看 test 表中的数据
mysql> select floor(rand(0) * 2),uname,concat(floor(rand(0) * 2), "Look Me") from test;
+--------------------+--------+---------------------------------------+
| floor(rand(0) * 2) | uname | concat(floor(rand(0) * 2), "Look Me") |
+--------------------+--------+---------------------------------------+
| 0 | admin | 0Look Me |
| 1 | admin1 | 1Look Me |
+--------------------+--------+---------------------------------------+
2 rows in set (0.00 sec)-- 04. 反直觉的:rand() + group by
mysql> select concat(floor(rand(0) * 2), "Look Me"),count(*) from test group by concat(floor(rand(0) * 2), "Look Me");
+---------------------------------------+----------+
| concat(floor(rand(0) * 2), "Look Me") | count(*) |
+---------------------------------------+----------+
| 1Look Me | 2 |
+---------------------------------------+----------+
1 row in set (0.00 sec)
上面 04 实例所展示的结果,是不是与我们的直觉相反,从 03 来看 concat(floor(rand(0) * 2), "Look Me")
查询出来的结果依次是:0Look Me
与 1Look Me
,所以按照道理,在计数时,最终展示的表格内容应该如下:
x | count(*) |
---|---|
0Look Me | 1 |
1Look Me | 1 |
但事实却是,1Look Me
被计数了两次。接下来,我们来理理为什么会出现这种结果。
先来看看下面这条语句的执行结果:
mysql> select concat(floor(rand(0) * 2), "Look Me") from test;
+---------------------------------------+
| concat(floor(rand(0) * 2), "Look Me") |
+---------------------------------------+
| 0Look Me |
| 1Look Me |
+---------------------------------------+
2 rows in set (0.00 sec)
当我们为其增加 count(*)
和 group by
后 MySQL 的运算过程如下:
首先,MySQL 会建立一张虚表,concat(floor(rand(0) * 2), "Look Me")
是主键,里面的值不可重复(我们将 concat(floor(rand(0) * 2), "Look Me")
简记为 Key,方便讲解):
concat(floor(rand(0) * 2), "Look Me") | count(*) |
---|---|
floor(rand(0) * 2)
结果序列:0110110011....
接下来,MySQL 会读取第一行 Key 的内容和虚表中的 Key 值进行比对,此时,MySQL 进行了第一次计算 concat(floor(rand(0) * 2), "Look Me")
,得到结果为 0LookMe
。MySQL 发现此值并不在虚表中存在,所以决定将此值插入到虚表中,并设置 count 值为 1。但是,就在 MySQL 准备将计算结果插入虚表时,由于 MySQL 的 Bug,导致 concat(floor(rand(0) * 2), "Look Me")
在插入之前又被计算了一次(第二次计算),导致 MySQL 实际插入的值为 1LookMe
,此时虚表中实际的内容为:
concat(floor(rand(0) * 2), "Look Me") | count(*) |
---|---|
1Look Me | 1 |
接着,MySQL 读取第二行 Key 的内容和虚表中的 Key 值进行比对,此时,MySQL 第三次计算了 concat(floor(rand(0) * 2), "Look Me")
,得到结果为 1LookMe
,该值在虚表中存在,所以 MySQL 就会直接执行插入操作(因为值在虚表中存在,所以不会触发 rand()
多次计算的 BUG),所以此时虚表展示的最终结果为:
concat(floor(rand(0) * 2), "Look Me") | count(*) |
---|---|
1Look Me | 1+1 |
这就是为什么最终我们看到的,和实际我们想象的不一样的原因。
接下来,我们往测试表中再次插入一条数据,触发 floor()
报错:
insert into test values(2,'admin2');mysql> select concat(floor(rand(0) * 2), "Look Me") from test;
+--------+---------------------------------------+
| uname | concat(floor(rand(0) * 2), "Look Me") |
+--------+---------------------------------------+
| admin | 0Look Me |
| admin1 | 1Look Me |
| admin2 | 1Look Me |
+--------+---------------------------------------+
3 rows in set (0.00 sec)
继续之前的分析,MySQL 读取第三行数据,第四次计算 concat(floor(rand(0) * 2), "Look Me")
的值为 0Look Me
,MySQL 发现虚表中没有该值对应的 Key,所以,准备执行插入操作。但是就在执行插入操作之前,由于 MySQL 的 Bug,其第五次计算了 concat(floor(rand(0) * 2), "Look Me")
,导致实际插入的结果为 1Look Me
,此时的虚表变成了:
xconcat(floor(rand(0) * 2), "Look Me") | count(*) |
---|---|
1Look Me | 2 |
1Look Me | ? |
可以看到,MySQL 认为自己插入的是 0Look Me
,但是由于 Bug,导致实际插入的是 1Look Me
,而 1Look Me
在虚表中是存在的,由于虚表的 Key 唯一的特性,所以 MySQL 此时就会产生报错:
select concat(floor(rand(0) * 2), "Look Me"),count(*) from test group by concat(floor(rand(0) * 2), "Look Me");
3.3 floor() 报错实例
以下是一个使用 floor()
函数进行报错注入的攻击示例:
select concat(0x7e,user(),0x7e,floor(rand(0)*2))x,count(*) from test group by x;
4. ceil() - 虚表主键重复报错
4.1 ceil() 函数简介
MySQL 中的 ceil()
函数用于返回大于或等于指定数值的最小整数:
-- ceil() 语法
CEIL(number)-- ceil() 参数解析
number : 需要向上取整的数值表达式。可以是列名、数值、算数表达式或函数返回值。
以下是该函数的一个正确的使用示例:
select ceil(4.1);
4.2 ceil() 报错原理
ceil()
报错注入的原理与上面讲解的 floor() 报错原理 一致,所以这里就不多说了。
4.3 ceil() 报错实例
以下是一个使用 ceil()
函数进行报错注入的攻击实例:
select concat(0x7e,user(),0x7e,ceil(rand(0)*2))x,count(*) from test group by x;
0x02:报错盲注 —— 实战篇
本节重点在于熟悉报错盲注的注入流程,以及注入原理。练习靶场为 Sqli-labs Less-1 GET - Error based - Single Quotes - String,靶场的配套资源如下(附安装教程):
实验工具准备
PHP 运行环境:phpstudy_x64_8.1.1.3.zip(PHP 7.X + Apache + MySQL)
SQLI LABS 靶场:sqli-labs-php7.zip(安装教程:Sqli-labs Less-1 GET - Error based - Single Quotes - String)
0x0201:第一阶段 — 判断注入点
靶场提示 Please input the ID as parameter with numeric value
要我们输入一个数字型的 ID
作为参数进行查询,那我们就按它的意思传入 id
看看网页返回的结果:
可以看到,服务器返回了对应 id
用户的登录名与登录密码。此时,我们可以再输入几个数据进行测试:
测试 Payload 01: ?id=1 # 结果: Your Login name:Dumb Your Password:Dumb
测试 Payload 02: ?id=2 # 结果: Your Login name:Angelina Your Password:I-kill-you
测试 Payload 03: ?id=2-1 # 结果: Your Login name:Angelina Your Password:I-kill-you
测试 Payload 04: ?id=1' # 结果: 报错
可以看到,当我们传递 Payload 04 给服务器后端时,页面显示了报错信息,并且还返回了部分后端的查询模板。
0x0202:第二阶段 — 报错盲注漏洞利用
既然能显示报错信息,那么本关我们就可以直接使用报错注入(使用 Union 联合注入也是可以的,但是,从本关的名称 Error based
就可以看出,本关的考点是报错注入),攻击 Payload 如下:
-- 获取当前服务器正在使用的数据库的名称
攻击 Payload: ?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+'
笔者备注: 0x7e 是字符 ~ 号,用于标识服务器报出来的数据。
可以看到,我们已经成功获取了当前站点使用的后端数据库的信息。以上,就是报错盲注的基本利用方式。后面想查啥,直接往报错注入的回显点里写就可以了,笔者在这里就不多说了。
相关文章:

SQL Injection | SQL 注入 —— 报错盲注
关注这个漏洞的其他相关笔记:SQL 注入漏洞 - 学习手册-CSDN博客 0x01:报错盲注 —— 理论篇 报错盲注(Error-Based Blind SQL Injection)是一种常见的 SQL 注入技术,适用于那些页面不会直接显示后端处理结果的查询方式…...

网络通信与并发编程(四)操作系统、进程理论、开启进程的两种方式
多道技术、进程理论 文章目录 多道技术、进程理论一、操作系统1.1操作系统1.2操作系统中的常见概念1.3操作系统的发展史 二、进程理论2.1同步、异步、阻塞、非阻塞2.2 进程的层次结构2.3 运行态、阻塞态、就绪态 三、开启进程的两种方式3.1使用Process创建进程的两种方式3.2 父…...

Java--集合(三)之vectorlinkedlisthashset结构
文章目录 0.架构图1.vector解析2.LinkedList分析2.1源码分析2.2迭代器遍历的三种方式 3.set接口的使用方法3.1基本使用说明3.2基本遍历方式3.3HashSet引入3.4数组链表模拟3.5hashset扩容机制3.6hashset源码解读3.7扩容*转成红黑树机制**我的理解 0.架构图 1.vector解析 和之前介…...

upload-labs Pass-04
upload-labs Pass-04 在进行测试前,先了解一下.htaccess文件 .htaccess文件 .htaccess是Apache网络服务器一个配置文件,当.htaccess文件被放置在一个通过Apache Web服务器加载的目录中,.htaccess文件会被Apache Web服务器软件检测并执行&…...

如何修改jupyter notebook的工作目录
1.生成配置文件: 打开Anaconda Prompt,输入如下命令 jupyter notebook --generate-config 用代码可以找到配置文件位置,如果没有填y可以生成。 2.修改配置文件: 修改jupyter_notebook_config.py的配置文件,需将c.Not…...
23种设计模式具体实现方法
提示:文章 文章目录 前言一、背景二、设计模式1、代理模式2、适配器模式2.1 总结 三、3.1 总结 前言 前期疑问: 本文目标: 一、背景 最近 二、设计模式 1、代理模式 参考的这篇文章,代理模式(Proxy) 同时这篇文章还引用了另…...

cisco网络安全技术第3章测试及考试
测试 使用本地数据库保护设备访问(通过使用 AAA 中央服务器来解决)有什么缺点? 试题 1选择一项: 必须在每个设备上本地配置用户帐户,是一种不可扩展的身份验证解决方案。 请参见图示。AAA 状态消息的哪一部分可帮助…...

数据结构练习题5(链表和栈)
1环形链表 II 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测…...

计算机网络408真题解析(湖科大教书匠)
09年...

uniapp+vue3+uview-plus修改默认样式
最近使用uniappvue3uview-plus开发微信小程序中,使用uview-plus自定义底部导航栏tabbar时,遇到修改默认样式不生效问题 使用传统的 ::v-deep、:deep、::v-deep,或者style标签中去掉scoped也是无效的,有好的方案欢迎交流ÿ…...

数控机械制造工厂ERP适用范围有哪些
在当今制造业高速发展的背景下,企业资源计划(ERP)系统已成为提升工厂管理效率、实现生产自动化与信息化的关键工具。特别是对于数控机械制造工厂而言,一个合适的ERP系统能够帮助其优化生产流程、提高产品质量、降低生产成本并增强市场竞争力。 1. 生产计…...

华为配置 之 Console线路配置
目录 简介: 知识点: 配置Console线路密码 1.密码认证模式 2.AAA认证模式 知识点: 总结: 简介: 使用PC模拟器与路由器相连(与交换机相连原理一样),在关机状态下,使用…...
小米等手机彻底关闭快应用
文章目录 快应用的是非最终措施:撤销快应用隐私协议配套措施:安卓去除开屏广告 无用的操作:载快应用小米手机无用,其他手机可以尝试的操作关闭唤起快应用服务打开防止误触、后台启动其他应用 其他措施:冻结、加密快应用…...

【每日一题】24.10.14 - 24.10.20
10.14 直角三角形1. 题目2. 解题思路3. 代码实现(AC_Code) 10.15 回文判定1. 题目2. 解题思路3. 代码实现(AC_Code) 10.16 二次方程1. 题目2. 解题思路3. 代码实现(AC_Code) 10.17 互质1. 题目2. 解题思路3…...
CMake与Qt4/Qt5的结合使用指南
CMake与Qt4/Qt5的结合使用指南 一、同时使用Qt 4和Qt 5二、Qt构建工具2.1 AUTOMOC2.2 AUTOUIC2.3 AUTORCC 三、<ORIGIN>_autogen目标四、Visual Studio生成器五、Windows上的qtmain.lib六、其他文章推荐 在CMake中,您可以方便地找到并使用Qt 4和Qt 5库。Qt 4库…...

TwinCAT3添加PLC轴,并建立PLC轴与NC轴的链接
右键PLC选项,点击创建新项 在弹出的对话框中,选择PLC Templates,然后选择Standard PLC Project,填写项目名称后点击添加 在PLC项目目录中右键GVLs,选择Add,添加Global Variable List(全局变…...

Linux操作系统如何制作U盘启动盘
在麒麟系统中有一款U盘启动器软件,它是用于制作系统启动U盘的工具,方便无光驱的电脑安装操作系统,也可以反复使用一个U盘,避免光盘的浪费。下面对该U盘启动器使用方法做详细讲解。 1.准备需要安装的系统镜像文件。 图 1 2.准备1…...

如何防止SpringBoot中的jar反编译?解决相关报错及踩到的坑
目录 1. 面对的场景 2. 方案 2.1 使用代码混淆 2.2 JAR包加密 3. 项目操作 4. 启动方式 5. 踩到的各种坑 5.1 java -jar xxx-0.0.1-SNAPSHOT.jar 没有主清单属性 5.2 Caused by: java.lang.IllegalArgumentException: Unrecognized option: -pwdfxw-jar 1. 面对的场景…...
Axios 基本使用
Axios 是一个异步请求技术,核心作用就是用来在页面中发送异步请求,并获取对应数据在页面中渲染 页面局部更新技术 Ajax 中文网站:https://www.kancloud.cn/yunye/axios/234845 安装: <script src"https://unpkg.com/axios/dist/axios.min.js"></script&g…...
前端大佬都在用的actionDelegationMiddleware究竟有多香?
作为一个前端开发者,我深知跨组件通信的痛点。今天,我要和大家分享一个让我眼前一亮的工具 - alovajs 的 actionDelegationMiddleware。这个中间件简直就是跨组件通信的得力助手!它让我们可以在任意组件中触发其他组件的请求操作,解决了很多麻烦。用了它之后,我感觉整个项目的架…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...