l1n6yun's Blog

记录学习的技能和遇到的问题

Superfetch 服务是什么

Superfetch,直译为 “超级预取” ,是 Windows 系统中的一项智能服务,最早在 Windows Vista 系统中引入,后续的 Windows 7、Windows 8 以及 Windows 10 等系统版本也都沿用了这一功能,其核心作用在于提升系统和应用程序的运行速度。

它的运行原理基于对用户使用习惯的深度学习与分析。当我们日常使用电脑时,Superfetch 会在后台默默监控我们频繁开启的各类程序。一旦它 “熟悉” 了我们的使用模式,就会将这些常用程序运行时所依赖的数据和代码,提前加载到内存之中。就好比你每天早上出门前,会提前把当天要用的文件准备好放在包里,等真正需要的时候,就能迅速拿出来使用,无需再临时翻找。

举个简单的例子,假如你每天上班打开电脑后的第一件事就是启动微信与同事沟通工作,那么 Superfetch 服务就会 “记住” 这个习惯。在你下次开机时,它会提前将微信运行所需的关键文件和数据从硬盘读取到内存里。这样一来,当你点击微信图标时,程序便能从内存中快速获取所需内容,实现几乎瞬间启动,大大节省了等待时间,让你的工作衔接更加顺畅高效。又或者你经常使用 Photoshop 处理图片,Superfetch 也会将 Photoshop 运行时可能用到的图像算法库、常用滤镜数据等提前加载,使得你在启动 Photoshop 以及使用各种功能时,响应速度明显加快,创作过程更加流畅。

不过,Superfetch 在发挥作用的过程中,也会对系统资源产生一定的占用。它需要消耗一定的 CPU 运算资源来分析用户行为模式,同时还会占用一部分内存空间用于存放预读取的数据,这也是我们在考虑是否禁用它时需要权衡的因素。

为什么有人想禁用 Superfetch 服务

尽管 Superfetch 服务出发点是好的,旨在提升系统性能,但在实际使用中,不少用户却萌生出禁用它的想法,这背后有着多方面的原因。

占用过多系统资源

Superfetch 服务在运行过程中,对系统资源有着较高的需求。它需要持续分析用户的使用习惯,这一过程会占用一定的 CPU 资源,尤其是在系统刚刚启动或者用户使用习惯发生较大变化时,CPU 的占用率会明显上升,导致电脑在这段时间内反应迟缓,打开其他程序时也会出现卡顿现象。比如,当你早上开机后,想要快速打开多个办公软件开始一天的工作,却发现电脑变得异常迟钝,很可能就是 Superfetch 服务在后台大量占用 CPU 资源,使得其他程序无法及时获取足够的运算资源来启动。

同时,Superfetch 会将预读取的数据存储在内存中,这无疑会占用相当一部分内存空间。对于那些内存容量本身就不大的电脑来说,这可能会导致系统内存紧张。当内存不足时,系统会频繁地进行内存与硬盘之间的数据交换,也就是我们常说的 “虚拟内存” 操作,这会大大降低系统的运行效率,使电脑整体变得卡顿,严重影响用户体验。

对 SSD 优化作用小

在固态硬盘(SSD)普及之前,Superfetch 服务对于提升机械硬盘的读取速度效果显著。因为机械硬盘的读写速度相对较慢,通过预读取数据到内存,可以有效减少等待时间。然而,随着 SSD 的广泛应用,情况发生了变化。SSD 采用闪存芯片作为存储介质,其随机读写速度比机械硬盘快了数倍甚至数十倍,能够在极短的时间内读取大量数据。在这种情况下,Superfetch 服务提前预取数据的优势就不再那么明显,其对系统性能的提升效果变得微乎其微。许多用户发现,即使禁用了 Superfetch 服务,使用 SSD 的电脑在程序启动速度和系统响应速度上依然表现出色,并没有因为缺少了 Superfetch 的预取功能而受到明显影响。

导致硬盘占用率高

有时候,Superfetch 服务可能会出现异常情况,导致硬盘占用率居高不下。这是因为它在预取数据时,可能会频繁地对硬盘进行读写操作。当硬盘的读写任务过于繁重时,就会出现 100% 占用的情况,此时电脑会变得异常卡顿,几乎无法进行正常操作。比如,你正在使用电脑进行视频剪辑或者玩大型游戏,突然发现电脑变得反应迟缓,打开文件或者切换程序都要等待很长时间,查看任务管理器后发现硬盘占用率达到了 100%,而罪魁祸首很可能就是 Superfetch 服务。这种异常情况不仅会影响当前正在进行的工作和娱乐,还可能对硬盘的寿命产生一定的影响。

禁用 Superfetch 服务的详细步骤

不同版本的 Windows 系统,禁用 Superfetch 服务的方法略有差异,下面分别为大家介绍 Windows 7、Windows 10 和 Windows 11 系统下的具体操作步骤。

Windows 7 系统

  1. 打开服务管理器:同时按下键盘上的Win + R组合键,调出 “运行” 对话框,在对话框中输入services.msc,然后按下回车键Enter,即可打开服务管理器窗口。

  2. 找到 Superfetch 服务:在服务管理器窗口中,会显示出众多系统服务,这些服务按照字母顺序排列。我们需要在列表中仔细查找名为 “Superfetch” 的服务。

  3. 停止 Superfetch 服务:找到 “Superfetch” 服务后,双击该服务,打开其属性窗口。在属性窗口的 “常规” 标签页中,将 “启动类型” 从原来的 “自动” 设置为 “已禁用”。设置完成后,点击 “停止” 按钮,此时 Superfetch 服务就会停止运行。

  4. 保存设置:点击 “确定” 按钮,保存我们所做的更改设置。这样,在下次系统启动时,Superfetch 服务就不会自动运行了。

Windows 10 系统

  1. 打开计算机管理:在 Windows 10 桌面,右键点击 “此电脑” 图标,在弹出的菜单中选择 “管理” 菜单项,即可打开计算机管理窗口。

  2. 进入服务选项:在打开的计算机管理窗口中,点击左侧列表中的 “服务和应用程序” 一项,展开该项后,再点击 “服务” 菜单项 ,此时在窗口右侧会显示出所有的系统服务列表。

  3. 找到并设置 Superfetch 服务:在服务列表中找到 “superfetch” 一项,双击它打开 “superfetch” 的属性窗口。首先点击 “停止” 按钮,关闭当前正在运行的 superfetch 服务。然后为了防止下次开机时该服务自动启动,点击 “启动类型” 下拉菜单,在弹出的菜单中选择 “禁用” 菜单项。

  4. 确认保存:完成上述设置后,点击 “确定” 按钮保存设置,关闭属性窗口即可。

Windows 11 系统

  1. 使用服务应用程序:按下Windows+S组合键启动 “搜索” 菜单,在顶部的文本字段中输入 “服务”,然后单击相关搜索结果。在打开的服务窗口中找到 “SysMain” 条目(在 Windows 11 中 Superfetch 服务改名为 SysMain ),右键单击它,然后从上下文菜单中选择 “属性”,或者直接双击该服务。在弹出的属性窗口中,单击 “启动类型” 下拉菜单,然后从选项列表中选择 “禁用”。接下来,如果当前服务正在运行,请单击 “服务状态” 下的 “停止” 按钮,最后单击底部的 “确定” 以保存更改。完成后重新启动计算机,以使更改生效。

  2. 使用命令提示符:按下Windows+S组合键启动搜索菜单,在文本字段中输入 “终端”,右键单击相关搜索结果,然后从上下文菜单中选择 “以管理员身份运行”。在弹出的用户帐户控制(UAC)提示中单击 “是”。单击顶部的向下箭头,然后选择 “Command Prompt”(命令提示符)。或者,也可以按下Ctrl+Shift+2组合键在新选项卡中启动命令提示符。在命令提示符窗口中,粘贴以下命令并点击Enter键停止服务:net.exe stop sysmain。接着,执行以下命令以禁用 Superfetch 在启动时加载:sc config sysmain start=disabled

  3. 使用注册表编辑器:按下Windows+R组合键启动运行命令,在文本字段中输入regedit,然后单击 “确定” 或点击Enter键启动注册表编辑器。在弹出的 UAC 提示中单击 “是”。在注册表编辑器中,将以下路径粘贴到顶部的地址栏中,然后点击Enter键,或者也可以使用左侧的导航窗格依次展开路径:Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters。在该路径下,右键单击空白区域,将光标悬停在 “新建” 上,然后从上下文菜单中选择 “DWORD(32 位)值”。将该条目命名为 “EnableSuperfetch”,然后双击它以修改属性。在 “数值数据” 下的文本字段中输入 “0” ,然后单击 “确定” 以保存更改。进行更改后,重新启动计算机以使更改生效。不过使用注册表编辑器时需格外小心,错误的修改可能会导致系统出现严重问题。

禁用 Superfetch 服务后的影响

禁用 Superfetch 服务,犹如在电脑的系统生态中做出一次关键的 “调整”,这一操作会带来多方面的影响,既可能有性能提升的惊喜,也可能伴随着一些负面效应,需要我们全面客观地去看待。

可能的性能提升

  1. 释放系统资源:正如前文所提到的,Superfetch 服务在运行时会占用一定的 CPU 和内存资源。当我们禁用它后,这些被占用的资源将被释放出来,可供其他程序使用。对于那些配置相对较低的电脑而言,这无疑是个好消息。例如,一台只有 4GB 内存的笔记本电脑,在禁用 Superfetch 服务后,原本被其占用的几百 MB 内存得以释放,电脑在运行多个程序时,内存不再那么紧张,程序之间的切换也变得更加流畅,不容易出现因内存不足而导致的卡顿现象。

  2. 减少硬盘读写:Superfetch 服务为了实现预取功能,会频繁地对硬盘进行读写操作。尤其是在系统启动和程序运行初期,这种读写操作更为明显。禁用该服务后,硬盘的读写负担将大大减轻。对于使用机械硬盘的电脑来说,这可以有效减少硬盘的磨损,延长硬盘的使用寿命;而对于固态硬盘,虽然其读写速度快,但减少不必要的读写操作也有助于降低固态硬盘的写入放大效应,从而延长其寿命,同时也能减少因硬盘读写而产生的热量。

  3. 特定场景下的性能提升:在某些特定场景中,禁用 Superfetch 服务能够显著提升系统性能。比如,对于一些追求极致游戏性能的玩家来说,在玩大型游戏时,禁用 Superfetch 服务可以避免其在后台占用资源,使游戏能够获得更多的系统资源,从而提升游戏的帧率和稳定性,减少游戏过程中的卡顿现象,让玩家能够更加流畅地享受游戏带来的乐趣。又或者对于从事视频剪辑、3D 建模等对系统性能要求较高的专业用户来说,禁用 Superfetch 服务后,他们在使用这些专业软件时,软件的响应速度会更快,操作更加流畅,能够大大提高工作效率。

潜在的负面影响

  1. 系统启动和程序加载变慢:Superfetch 服务的核心作用是提前预取系统和程序运行所需的数据,从而加快系统启动和程序加载速度。一旦禁用它,系统在启动时就无法提前将常用程序的数据加载到内存中,程序在启动时也需要从硬盘中实时读取数据,这必然会导致系统启动时间变长,程序的首次加载速度明显变慢。例如,原本开机后几秒钟就能快速启动的微信,在禁用 Superfetch 服务后,可能需要等待十几秒甚至更长时间才能打开,这对于那些追求高效、希望能够快速进入工作或娱乐状态的用户来说,无疑是一种困扰。

  2. 内存管理可能受影响:Superfetch 服务在一定程度上参与了系统的内存管理,它通过分析用户的使用习惯,合理地将数据预加载到内存中,使得内存的使用更加高效。当禁用该服务后,系统的内存管理可能会受到一定影响。内存中可能无法及时存放常用程序的数据,导致程序在运行过程中频繁地进行内存与硬盘之间的数据交换,增加了系统的负担,进而可能影响到系统的整体性能和稳定性,使电脑在运行多个程序时容易出现卡顿现象。

  3. 影响用户体验:从整体用户体验的角度来看,禁用 Superfetch 服务带来的启动和加载变慢问题,可能会让用户在日常使用电脑的过程中感到烦躁和不便。尤其是在当今快节奏的生活和工作环境下,时间的碎片化使得用户希望每一次使用电脑都能够快速、高效地完成任务,而这种等待时间的增加无疑与用户的期望背道而驰,可能会降低用户对电脑使用的满意度 。

如何判断是否适合禁用 Superfetch 服务

禁用 Superfetch 服务并非适用于所有用户和所有电脑,在决定是否禁用之前,我们需要综合多方面因素进行判断,找到最适合自己电脑的设置方案 。

依据电脑配置判断

  1. 低配置电脑:如果你的电脑配置较低,例如 CPU 性能较弱、内存容量较小(4GB 及以下),且使用的是机械硬盘,那么禁用 Superfetch 服务可能会为你带来一定的性能提升。因为这类电脑本身资源有限,Superfetch 服务占用的资源可能会对其他程序的运行产生较大影响。禁用它后,可以释放出更多的系统资源,让电脑运行更加流畅。

  2. 高配置电脑:对于高配置电脑,如配备高性能 CPU、大容量内存(16GB 及以上)以及快速的固态硬盘,Superfetch 服务所占用的资源相对来说对系统整体性能的影响较小。在这种情况下,保留 Superfetch 服务可能会使系统和程序的启动速度更快,用户体验更好,因此不一定需要禁用它。

根据使用习惯判断

  1. 固定使用场景:如果你每天使用电脑的场景比较固定,总是运行相同的几个程序,那么 Superfetch 服务能够很好地发挥其预取作用,提前加载常用程序,减少等待时间。这种情况下,保留该服务会更符合你的使用需求。比如,你是一名上班族,每天主要使用办公软件(Word、Excel、PPT)、通讯工具(微信、QQ)以及浏览器进行工作,Superfetch 服务能够根据你的使用习惯,提前将这些程序所需的数据加载到内存中,让你能够快速进入工作状态。

  2. 频繁切换使用场景:然而,如果你经常在不同的使用场景之间切换,运行各种不同类型的程序,Superfetch 服务可能无法及时准确地预取到你需要的数据。因为它需要一定的时间来分析你的新使用习惯并进行预取,在这种频繁变化的情况下,其预取效果可能并不理想,此时禁用它可能不会对你的使用造成太大影响。

参考系统性能表现判断

  1. 系统卡顿明显:如果你在日常使用电脑的过程中,经常遇到系统卡顿、反应迟缓的情况,并且通过任务管理器等工具发现 Superfetch 服务占用了大量的 CPU、内存或硬盘资源,那么可以尝试禁用该服务,观察系统性能是否有所改善。例如,在打开多个程序时,电脑出现长时间无响应,查看任务管理器发现 Superfetch 服务占用了较高的 CPU 资源,此时禁用它可能会使系统恢复流畅。

  2. 系统运行流畅:相反,如果你的电脑在运行过程中一直表现得很流畅,系统和程序的启动速度也能满足你的需求,那么就没有必要冒险去禁用 Superfetch 服务,以免带来不必要的负面影响。

总结与建议

禁用 Superfetch 服务,是一把双刃剑,有着明显的利弊两面。从积极的方面来看,它能够释放系统资源,减少对 CPU、内存和硬盘的占用,尤其对于低配置电脑以及机械硬盘,在一定程度上可提升系统运行的流畅度,降低硬盘的读写负担,延长硬盘使用寿命。同时,在特定的使用场景下,比如追求极致游戏性能或专业软件运行效率时,能让电脑将更多资源集中于关键任务,带来更好的性能表现。

然而,我们也不能忽视其负面效应。禁用 Superfetch 服务后,系统启动和程序加载速度会明显变慢,这会在日常使用中增加等待时间,降低工作和娱乐的效率。而且,它还可能影响系统的内存管理机制,导致内存使用不够合理,进而影响系统的整体稳定性和性能。

对于不同用户群体,建议如下:如果你的电脑配置较低,且使用场景较为单一,日常主要运行少数几个固定程序,那么可以尝试禁用 Superfetch 服务,通过释放系统资源来提升电脑的运行流畅度。但在操作之前,务必备份好重要数据,以防万一。

而对于高配置电脑用户,若电脑在运行过程中没有出现明显的资源不足或卡顿问题,保留 Superfetch 服务通常能获得更便捷、高效的使用体验,因为它可以让系统和程序的启动更加迅速。

总之,是否禁用 Superfetch 服务,需要我们根据自身电脑的实际配置、使用习惯以及系统性能表现等多方面因素,进行全面、谨慎的考虑和权衡。在操作过程中,一定要谨慎行事,尤其是涉及到修改系统服务和注册表等关键设置时,以免因不当操作导致系统出现严重问题,影响正常使用。

在 Alpine Linux 环境中使用 PhpStorm 的 Git 工具时,部分开发者可能会遇到以下错误提示,导致版本控制功能无法正常使用。本文将详细分析问题成因并提供分步解决方案。

错误呈现

当尝试在 PhpStorm 中更新代码或执行 Git 操作时,控制台会抛出以下异常:

1
2
3
4
5
6
7
8
9
Error updating changes: setsid: unrecognized option: w
BusyBox v1.36.1 (2024-06-12 11:52:11 UTC) multi-call binary.

Usage: setsid [-c] PROG ARGS

Run PROG in a new session. PROG will have no controlling terminal
and will not be affected by keyboard signals (^C etc).

-c Set controlling terminal to stdin

upload successful

关键问题点:BusyBox 提供的 setsid 命令不支持-w选项,而 PhpStorm 的 Git 工具可能默认调用了该参数,导致命令执行失败。

问题分析

Alpine Linux 默认使用 BusyBox 工具集,其内置的setsid命令仅支持-c选项(设置控制终端),但 PhpStorm 等 IDE 的 Git 插件可能依赖 GNU Core Utilities 中的setsid命令(支持更多选项,如-w)。由于 BusyBox 的setsid与 GNU 版本存在兼容性差异,导致 IDE 调用时参数不匹配。

解决方法

以下操作需在终端中以管理员权限(sudo)执行,逐步修复命令冲突问题:

1. 查看系统当前 setsid 指向

1
2
cd /usr/bin/
ls -al | grep setsid

upload successful

  • 可见当前setsid实际指向 BusyBox 的busybox二进制文件(通过软链接setsid2)。

2. 重命名原有 setsid 软链接

1
mv setsid setsid2
  • 此步骤避免原有 BusyBox 版本的setsid与后续安装的 GNU 版本冲突。

3. 安装 GNU Core Utilities 并拷贝 setsid

Alpine 默认仓库中的coreutils包提供 GNU 版本的工具集,执行以下命令安装并复制setsid

下载地址:setsid

1
cp setsid /usr/bin/setsid

注意:若coreutils安装后setsid路径不同(如/usr/bin/setsid已存在),请根据实际路径调整拷贝命令。

4. 设置执行权限

1
chmod 777 /usr/bin/setsid
  • 赋予文件完整权限,确保 PhpStorm 可正常调用。

upload successful

验证修复效果

  1. 重启 PhpStorm,再次尝试 Git 操作(如拉取、提交代码)。
  2. 若控制台不再出现setsid: unrecognized option: w错误,则说明修复成功。
  3. 如需进一步验证,可在终端直接执行setsid -w echo test,若正常输出test且无报错,表明 GNU 版本的setsid已生效。

补充说明

  • 原理总结:通过替换 BusyBox 的setsid为 GNU 版本,解决 IDE 参数调用不兼容问题。
  • 注意事项:修改系统二进制文件需谨慎操作,建议提前备份原有文件(如复制setsid2到其他目录)。
  • 扩展场景:类似问题可能出现在其他依赖 GNU 工具的 IDE 或脚本中,均可通过安装coreutils并替换对应命令解决。

通过以上步骤,即可在 Alpine 系统中恢复 PhpStorm 的 Git 工具正常使用,确保开发流程不受环境差异影响。

MySQL 递归 CTE 基础概念

1 什么是递归 CTE?

递归公用表表达式(Recursive CTE)是 MySQL 8.0 引入的高级特性,通过WITH RECURSIVE语法定义,允许在 CTE 内部递归引用自身,专门用于处理具有层级关系的树形数据,如组织架构、分类目录、文件系统等。其核心思想是通过锚成员(初始查询)和递归成员(迭代查询)的结合,逐层扩展结果集,直至满足终止条件(递归成员返回空集)。

2 适用场景

组织架构管理:查询某个部门的所有上下级节点。

分类目录遍历:获取商品分类的全层级路径。

树状结构分析:查找节点的所有祖先或后代,替代传统自连接或存储过程的复杂逻辑。

递归 CTE 语法解析与执行逻辑

1 核心语法结构

1
2
3
4
5
6
7
8
9
10
WITH RECURSIVE cte_name (column_list) AS (
-- 锚成员:定义递归初始条件,返回基础结果集
initial_query
UNION ALL -- 必须使用UNION ALL,确保递归过程高效合并结果
-- 递归成员:引用CTE名称,定义迭代规则
recursive_query
)

-- 最终查询:基于CTE结果集进行筛选或关联
SELECT ... FROM cte_name;

2 执行流程详解

锚成员执行:生成初始结果集(R0),如指定节点的基础信息。

递归迭代:将上一次结果集(Ri)作为输入,通过UNION ALL合并新生成的结果集(Ri+1),直到递归成员返回空集。

终止条件:隐式终止于递归成员无数据返回,或显式通过条件(如WHERE n < 100)限制递归深度。

3 递归成员限制

禁止使用聚合函数(如SUM/COUNT)、GROUP BYORDER BYLIMITDISTINCTUNION DISTINCT除外)。

仅能引用 CTE 名称,不能嵌套子查询。

典型场景与实战案例

1 查询节点所有父节点(向上递归)

场景:从子节点出发,逐层查找所有上级节点(如员工查询其所有管理层级)。表结构club(id, name, pid)pid为父节点 ID,根节点pidNULLSQL 示例

1
2
3
4
5
6
7
8
9
WITH RECURSIVE parent_path AS (
-- 锚成员:初始节点(如id=5的子节点)
SELECT id, name, pid FROM club WHERE id = 5
UNION ALL
-- 递归成员:通过pid关联,获取父节点
SELECT p.id, p.name, p.pid FROM club p JOIN parent_path pp ON p.id = pp.pid
)

SELECT * FROM parent_path;

解析:从 id=5 开始,每次递归通过pid找到父节点,直至无更高层级节点。

2 查询节点所有子节点(向下递归)

场景:从父节点出发,获取其所有直接及间接子节点(如部门主管查询下属团队)。SQL 示例

1
2
3
4
5
6
7
8
WITH RECURSIVE child_path AS (
SELECT id, name, pid FROM club WHERE id = 3 -- 锚成员:初始父节点
UNION ALL
-- 递归成员:通过子节点pid关联父节点id
SELECT c.id, c.name, c.pid FROM club c JOIN child_path cp ON c.pid = cp.id
)

SELECT * FROM child_path;

解析:以 id=3 为起点,逐层匹配pid=当前id的子节点,实现无限层级遍历。

3 添加层级标识(Level 字段)

场景:在查询结果中显式节点层级,方便分页或排序(如目录树展示)。SQL 示例

1
2
3
4
5
6
7
8
9
10
WITH RECURSIVE level_tree AS (
SELECT id, name, pid, 1 AS level FROM club WHERE id = 1 -- 根节点层级为1
UNION ALL
SELECT c.id, c.name, c.pid, ct.level + 1 AS level -- 子节点层级=父层级+1
FROM club c JOIN level_tree ct ON c.pid = ct.id
)

-- 筛选层级>3的深层子节点

SELECT id, name, pid, level FROM level_tree WHERE level > 3;

解析:通过level字段量化层级深度,避免表设计时预存层级的冗余问题。

4 实战优化:业务层与 SQL 层解耦

场景:传统 Java/Python 代码中,递归遍历组织架构易导致性能瓶颈,改用递归 CTE 后可在数据库层高效完成。MyBatis 映射示例

1
2
3
4
5
6
WITH RECURSIVE DeptTree AS (
SELECT id_ FROM org_group WHERE id_ = #{deptId} -- 锚成员:目标部门
UNION ALL
SELECT og.id_ FROM org_group og JOIN DeptTree dt ON og.parent_id_ = dt.id_ -- 递归获取子部门
)
SELECT su.* FROM sys_user su JOIN DeptTree dt ON su.dept_id = dt.id_

优势:避免多次往返数据库,单条 SQL 完成层级查询,提升系统响应速度。

注意事项与最佳实践

1 MySQL 版本要求

仅支持 MySQL 8.0 及以上版本,低版本需使用存储过程或应用层递归实现。

2 避免死循环

数据校验:确保层级数据无环(如 A→B→A),否则递归会因无法终止报错(默认最大递归深度 1000,可通过SET @@cte_max_recursion_depth = N调整)。

条件限制:在递归成员中添加合理过滤条件(如WHERE level < 50),防止无限递归。

3 索引优化

idpid字段添加索引,提升递归过程中 JOIN 操作的效率,尤其对大规模层级数据至关重要。

4 结果去重

若数据存在重复关联,可在最终查询中使用DISTINCT去重,但需注意递归成员中禁止直接使用DISTINCT

总结

递归 CTE 是 MySQL 处理树形数据的 “瑞士军刀”,通过简洁的语法将复杂的层级查询转化为结构化的递归过程,显著提升开发效率与查询性能。无论是组织架构、分类目录还是其他层级场景,掌握递归 CTE 的锚成员定义、递归规则设计及终止条件把控,都能让你在数据处理中游刃有余。建议在实际项目中结合索引优化与数据校验,充分发挥其在层级查询中的优势。

动手实践:尝试在示例表club中插入多级数据,分别编写查询根节点、叶节点及全路径的递归 CTE 语句,观察结果差异与执行效率。

安装infinity插件

在插件页面中搜索 infinity,进入 infinity 插件页面点击 install,等待安装完成。

安装infinity插件

添加数据源

进入数据源页面,点击 Add new data source 按钮,搜索 infinity

搜索数据源

进入 infinity 数据源页面,输入 数据源 名称点击 Save & test

添加数据源

使用数据源

在仪表板中添加可视化,在 Data source 选项中选择刚刚新增的数据源。

URL 中填写你的接口地址。根据要求返回对应的格式即可呈现到面板上。

使用数据源

在使用 Burp Suite 进行 HTTP 请求或响应分析时,可能遇到请求参数、响应内容中的中文显示为乱码的情况,例如显示为乱码符号(如方框、问号等),影响数据查看和分析。

upload successful

Burp Suite 默认的字符编码或字体设置与中文不兼容,导致无法正确解析和显示中文字符。常见原因包括:
编码格式错误:未设置为 UTF-8(中文通用编码)。
字体不支持中文:默认字体无法渲染中文字符。

解决步骤

  1. 进入设置页面

    打开 Burp Suite,点击顶部菜单栏的 Settings(设置),选择 User Interface(用户界面)。

  2. 修改消息编辑器的编码和字体

    在左侧导航栏中选择 Message editor(消息编辑器)。

    在右侧的 Character sets(字符编码)下拉菜单中,选择 UTF-8(确保与目标网站的编码一致)。
    更换支持中文的字体:

    在 Font(字体)选项中,点击 Change font(选择字体),从列表中选择支持中文的字体(如 Microsoft YaHei、SimSun 或 黑体),调整字体大小至合适显示。

upload successful

修改完成后,就可以正常查看中文字体了

upload successful

PyAutoGUI 是什么

在 Python 的自动化领域中,PyAutoGUI 是一个非常实用的库,它允许我们通过编写代码来模拟鼠标和键盘的操作,从而实现自动化任务 。无论是重复性的日常工作,还是复杂的软件测试流程,PyAutoGUI 都能发挥重要作用,帮助我们节省时间和精力。

想象一下,你需要在某个软件中重复进行一系列的点击、输入操作,要是手动完成,不仅耗时,还容易出错。但有了 PyAutoGUI,你只需编写一个简单的 Python 脚本,就能让计算机自动执行这些任务。比如自动填写表格、批量处理文件、自动化测试软件功能等,这些操作都能轻松实现。

PyAutoGUI 的安装

在开始使用 PyAutoGUI 之前,我们需要先将其安装到我们的 Python 环境中。安装 PyAutoGUI 非常简单,使用 pip 命令即可完成 。打开你的命令行工具,输入以下命令:

1
pip install pyautogui

如果你使用的是 Python 3.9 或更高版本,也可以使用pip3命令进行安装:

1
pip3 install pyautogui

安装过程中,pip 会自动下载 PyAutoGUI 及其依赖项 。等待安装完成后,你就可以在 Python 脚本中导入并使用 PyAutoGUI 了。

需要注意的是,在安装之前,请确保你的 Python 环境已经正确配置,并且 pip 已经安装在系统上。如果你在 Windows 操作系统上使用 Python,还要确保已将 Python 添加到系统的环境变量中,以便能够在命令提示符中运行 pip。 如果你在安装过程中遇到问题,可以参考 PyAutoGUI 的官方文档,或者在相关技术论坛上寻求帮助。

PyAutoGUI 的强大功能展示

鼠标操作

1. 移动鼠标

在 PyAutoGUI 中,控制鼠标移动主要通过moveTo()和moveRel()函数 。moveTo()函数用于将鼠标移动到屏幕上的指定坐标位置,它的语法如下:

1
pyautogui.moveTo(x, y, duration=0)

其中,x和y是目标坐标的横坐标和纵坐标,duration是可选参数,表示鼠标移动到目标位置所需的时间,单位为秒。如果不设置duration,鼠标会瞬间移动到指定位置。例如,要将鼠标移动到屏幕坐标为 (500, 300) 的位置,可以使用以下代码:

1
2
3
4
import pyautogui

# 将鼠标移动到坐标(500, 300),耗时2秒
pyautogui.moveTo(500, 300, duration=2)

moveRel()函数则是相对于当前鼠标位置进行移动,语法为:

1
pyautogui.moveRel(xOffset, yOffset, duration=0)

xOffset和yOffset分别是水平和垂直方向上的偏移量,正数表示向右和向下移动,负数表示向左和向上移动。同样,duration是移动所需的时间。比如,要让鼠标在当前位置的基础上向右移动 100 个像素,向下移动 50 个像素,可以这样写:

1
2
3
4
import pyautogui

# 鼠标在当前位置基础上,向右移动100像素,向下移动50像素,耗时1秒
pyautogui.moveRel(100, 50, duration=1)

2. 点击操作

PyAutoGUI 提供了多个函数来实现鼠标的点击操作,包括click()、doubleClick()、rightClick()和middleClick()等 。click()函数是最常用的点击函数,它可以模拟鼠标的左键点击、右键点击以及中键点击,还可以设置点击的次数和间隔时间。语法如下:

1
pyautogui.click(x=None, y=None, clicks=1, interval=0.0, button='left')

x和y是点击的坐标位置,如果不指定则在当前鼠标位置点击;clicks表示点击的次数,默认为 1 次;interval是每次点击之间的间隔时间,单位为秒;button指定点击的鼠标按钮,可选值为 ‘left’。例如,要在坐标 (400, 200) 处进行两次左键点击,每次点击间隔 0.5 秒,可以使用以下代码:

1
2
3
4
import pyautogui

# 在坐标(400, 200)处进行两次左键点击,每次间隔0.5秒
pyautogui.click(400, 200, clicks=2, interval=0.5)

doubleClick()函数专门用于模拟鼠标左键的双击操作,语法为:

1
pyautogui.doubleClick(x=None, y=None, interval=0.0)

x和y是双击的坐标位置,interval是两次点击之间的间隔时间。例如:

1
2
3
4
import pyautogui

# 在当前鼠标位置进行双击
pyautogui.doubleClick()

rightClick()和middleClick()函数分别用于模拟鼠标右键点击和中键点击,语法类似,只需在调用时传入相应的坐标位置即可。例如:

1
2
3
4
5
6
7
import pyautogui

# 在坐标(300, 100)处进行右键点击
pyautogui.rightClick(300, 100)

# 在坐标(200, 150)处进行中键点击
pyautogui.middleClick(200, 150)

3. 鼠标拖拽

实现鼠标拖拽操作的函数是dragTo()和dragRel() 。dragTo()函数将鼠标从当前位置拖动到指定的坐标位置,语法如下:

1
pyautogui.dragTo(x, y, duration=0, button='left')

x和y是目标坐标,duration是拖动所需的时间,button指定拖动时使用的鼠标按钮,默认为左键。比如,要将鼠标从当前位置拖动到坐标 (600, 400) 处,耗时 3 秒,可以使用以下代码:

1
2
3
4
import pyautogui

# 从当前位置将鼠标拖动到坐标(600, 400),耗时3秒,使用左键
pyautogui.dragTo(600, 400, duration=3)

dragRel()函数则是相对于当前鼠标位置进行拖动,语法为:

1
pyautogui.dragRel(xOffset, yOffset, duration=0, button='left')

xOffset和yOffset是水平和垂直方向上的偏移量,duration是拖动时间,button是鼠标按钮。例如,要让鼠标在当前位置的基础上,向右拖动 80 个像素,向上拖动 30 个像素,耗时 2 秒,可以这样写:

1
2
3
4
import pyautogui

# 鼠标在当前位置基础上,向右拖动80像素,向上拖动30像素,耗时2秒,使用左键
pyautogui.dragRel(80, -30, duration=2)

4. 鼠标滚动

控制鼠标滚轮滚动的函数是scroll(),语法如下:

1
pyautogui.scroll(clicks)

clicks是一个整数参数,表示滚动的距离,正数表示向上滚动,负数表示向下滚动。例如,要让鼠标滚轮向上滚动 5 个单位,可以使用以下代码:

1
2
3
4
import pyautogui

# 鼠标滚轮向上滚动5个单位
pyautogui.scroll(5)

如果要向下滚动 10 个单位,则可以这样写:

1
2
3
4
import pyautogui

# 鼠标滚轮向下滚动10个单位
pyautogui.scroll(-10)

键盘操作

1. 按键模拟

在 PyAutoGUI 中,模拟按键按下和释放主要使用press()、keyDown()和keyUp()函数 。press()函数用于模拟按下并释放一个按键,语法如下:

1
pyautogui.press(key)

key是要按下的按键名称,可以是单个字符,如 ‘a’、’b’,也可以是特殊按键,如 ‘enter’等。例如,要模拟按下回车键,可以使用以下代码:

1
2
3
4
import pyautogui

# 模拟按下回车键
pyautogui.press('enter')

keyDown()函数用于模拟按下一个按键,而不释放,语法为:

1
pyautogui.keyDown(key)

keyUp()函数则用于模拟释放一个按键,语法为:

1
pyautogui.keyUp(key)

这两个函数通常一起使用,以实现对按键的精确控制。例如,要模拟按住 Shift 键的同时按下 ‘a’ 键,然后释放 Shift 键,可以这样写:

1
2
3
4
5
6
7
8
9
10
import pyautogui

# 按下Shift键
pyautogui.keyDown('shift')

# 按下'a'键
pyautogui.press('a')

# 释放Shift键
pyautogui.keyUp('shift')

2. 文本输入

实现自动化文本输入的函数是typewrite(),语法如下:

1
pyautogui.typewrite(message, interval=0.0)

message是要输入的文本内容,可以是字符串;interval是可选参数,表示输入每个字符之间的时间间隔,单位为秒。例如,要在当前光标位置输入 “Hello, World!”,每个字符之间间隔 0.2 秒,可以使用以下代码:

1
2
3
4
import pyautogui

# 输入"Hello, World!",每个字符间隔0.2秒
pyautogui.typewrite('Hello, World!', interval=0.2)

如果要输入包含特殊按键的组合,比如先按 ‘enter’ 键,再输入 “Python”,可以将按键和文本内容放在一个列表中传递给typewrite()函数,例如:

1
2
3
4
import pyautogui

# 先按'enter'键,再输入"Python"
pyautogui.typewrite(['enter', 'Python'])

3. 组合键操作

模拟组合键操作可以使用hotkey()函数,语法如下:

1
pyautogui.hotkey(*keys)

keys是要组合的按键名称,可以传递多个参数。例如,要模拟按下 Ctrl+C 组合键,可以使用以下代码:

1
2
3
4
import pyautogui

# 模拟按下Ctrl+C组合键
pyautogui.hotkey('ctrl', 'c')

同样,要模拟按下 Alt+Tab 组合键,可以这样写:

1
2
3
4
import pyautogui

# 模拟按下Alt+Tab组合键
pyautogui.hotkey('alt', 'tab')

屏幕操作

1. 屏幕截图

获取屏幕截图的函数是screenshot(),它可以返回一个表示屏幕截图的 Pillow 图像对象 。语法如下:

1
im = pyautogui.screenshot()

im就是返回的图像对象,你可以对其进行保存、分析等操作。例如,要将屏幕截图保存为名为 “screenshot.png” 的文件,可以使用以下代码:

1
2
3
4
import pyautogui

# 获取屏幕截图并保存为"screenshot.png"
im = pyautogui.screenshot()im.save('screenshot.png')

如果你只想截取屏幕的某个区域,可以使用region参数指定截取区域的左上角坐标和宽度、高度,语法如下:

1
im = pyautogui.screenshot(region=(left, top, width, height))

left和top是截取区域左上角的横坐标和纵坐标,width和height是截取区域的宽度和高度。例如,要截取屏幕左上角坐标为 (100, 100),宽度为 200,高度为 150 的区域,可以这样写:

1
2
3
4
import pyautogui

# 截取指定区域的屏幕截图
im = pyautogui.screenshot(region=(100, 100, 200, 150))im.save('partial_screenshot.png')

2. 图像识别定位

在屏幕上查找指定图像位置的函数主要有locateOnScreen()和locateCenterOnScreen() 。locateOnScreen()函数用于在屏幕上查找指定图像的位置,并返回其边界框的坐标,语法如下:

1
location = pyautogui.locateOnScreen(image, grayscale=False, confidence=None)

image是要查找的图像文件名或 Pillow 图像对象;grayscale是可选参数,设置为True时会以灰度模式查找图像,这样可以提高查找速度,但可能会降低准确性;confidence是可选参数,表示匹配的置信度,取值范围为 0 到 1,值越高表示匹配要求越严格,默认值为None,即不进行置信度匹配。location返回一个包含边界框坐标的四元组(left, top, width, height),如果未找到图像,则返回None。例如,要在屏幕上查找名为 “button.png” 的图像位置,可以使用以下代码:

1
2
3
4
5
6
7
8
import pyautogui

# 在屏幕上查找"button.png"的位置
location = pyautogui.locateOnScreen('button.png')
if location: left, top, width, height = location
print(f'找到图像,位置为:({left}, {top}),宽度为:{width},高度为:{height}')
else:
print('未找到图像')

locateCenterOnScreen()函数则是在屏幕上查找指定图像的位置,并返回其中心点的坐标,语法如下:

1
center = pyautogui.locateCenterOnScreen(image, grayscale=False, confidence=None)

center返回一个包含中心点坐标的二元组(x, y),如果未找到图像,则返回None。例如:

1
2
3
4
5
6
7
8
import pyautogui
# 在屏幕上查找"icon.png"的中心点位置
center = pyautogui.locateCenterOnScreen('icon.png')
if center:
x, y = center
print(f'找到图像,中心点位置为:({x}, {y})')
else:
print('未找到图像')

这些屏幕操作函数结合鼠标和键盘操作函数,可以实现更加复杂的自动化任务,比如根据屏幕上的图像位置进行点击、输入等操作。

实战应用案例

自动化测试

假设我们正在开发一款简单的图形界面应用程序,其中有一个登录窗口,包含用户名输入框、密码输入框和登录按钮 。我们可以使用 PyAutoGUI 编写自动化测试脚本来模拟用户登录操作,检查应用程序的登录功能是否正常。以下是一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import pyautogui
import time

# 模拟打开应用程序
app_icon_location = pyautogui.locateCenterOnScreen('app_icon.png')
if app_icon_location:
pyautogui.doubleClick(app_icon_location.x, app_icon_location.y)
time.sleep(3) # 等待应用程序打开

# 模拟输入用户名和密码
username_input_location = pyautogui.locateCenterOnScreen('username_input.png')
password_input_location = pyautogui.locateCenterOnScreen('password_input.png')
login_button_location = pyautogui.locateCenterOnScreen('login_button.png')

if username_input_location and password_input_location and login_button_location:
pyautogui.click(username_input_location.x, username_input_location.y)
pyautogui.typewrite('test_user')
pyautogui.click(password_input_location.x, password_input_location.y)
pyautogui.typewrite('test_password')
pyautogui.click(login_button_location.x, login_button_location.y)

time.sleep(2) # 等待登录结果显示

# 检查登录是否成功
success_dialog_location = pyautogui.locateOnScreen('success_dialog.png')
if success_dialog_location:
print('登录测试成功')
else:
print('登录测试失败')
else:
print('无法找到界面元素,测试终止')

在这个示例中,我们首先通过locateCenterOnScreen函数查找应用程序图标、用户名输入框、密码输入框和登录按钮的位置,然后使用click和typewrite函数模拟用户的点击和输入操作 。最后,通过查找登录成功后的提示框来判断登录是否成功。这样,我们就可以自动化地对应用程序的登录功能进行多次测试,大大提高了测试效率和准确性。

数据采集与处理

比如,我们需要从一个电商网站上采集商品信息,包括商品名称、价格、销量等 。我们可以使用 PyAutoGUI 结合一些图像识别和文本处理技术来实现自动化采集。以下是一个简单的思路和示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import pyautogui
import time
import pytesseract
from PIL import Image

# 打开浏览器并访问电商网站
pyautogui.hotkey('win', 'r') # 打开运行对话框
pyautogui.typewrite('chrome')
pyautogui.press('enter')
time.sleep(2)
pyautogui.typewrite('https://example_ecommerce.com')
pyautogui.press('enter')
time.sleep(5) # 等待页面加载

# 模拟搜索商品
search_box_location = pyautogui.locateCenterOnScreen('search_box.png')
if search_box_location:
pyautogui.click(search_box_location.x, search_box_location.y)
pyautogui.typewrite('手机')
pyautogui.press('enter')
time.sleep(5) # 等待搜索结果页面加载

# 采集商品信息
for _ in range(3): # 假设采集3页商品信息
# 截取当前页面商品信息区域的屏幕截图
screenshot = pyautogui.screenshot(region=(100, 200, 800, 600))
screenshot.save('product_info.png')

# 使用OCR识别截图中的文本信息
text = pytesseract.image_to_string(Image.open('product_info.png'))

# 处理识别出的文本,提取商品名称、价格、销量等信息
# 这里只是简单示例,实际需要更复杂的文本处理逻辑
lines = text.split('\n')
for line in lines:
if '价格' in line:
price = line.split(':')[-1]
print(f'商品价格:{price}')
elif '销量' in line:
sales = line.split(':')[-1]
print(f'商品销量:{sales}')

# 模拟点击下一页按钮
next_page_button_location = pyautogui.locateCenterOnScreen('next_page_button.png')
if next_page_button_location:
pyautogui.click(next_page_button_location.x, next_page_button_location.y)
time.sleep(5) # 等待下一页加载
else:
break

在这个示例中,我们首先打开浏览器并访问电商网站,然后模拟搜索商品 。接着,通过截取屏幕上商品信息区域的截图,并使用 OCR 技术识别截图中的文本,从而提取出商品的相关信息。最后,通过模拟点击下一页按钮,实现多页商品信息的采集。

软件演示与教程录制

假设我们要制作一个关于某个绘图软件使用教程的视频,我们可以使用 PyAutoGUI 自动化演示软件的各种功能,并配合录屏软件进行录制 。以下是一个简单的示例代码,展示如何使用 PyAutoGUI 打开绘图软件并进行一些基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import pyautogui
import time

# 模拟打开绘图软件
paint_icon_location = pyautogui.locateCenterOnScreen('paint_icon.png')
if paint_icon_location:
pyautogui.doubleClick(paint_icon_location.x, paint_icon_location.y)
time.sleep(5) # 等待软件打开

# 演示绘制一个矩形
rectangle_tool_location = pyautogui.locateCenterOnScreen('rectangle_tool.png')
if rectangle_tool_location:
pyautogui.click(rectangle_tool_location.x, rectangle_tool_location.y)
time.sleep(1)

start_x, start_y = 100, 100
end_x, end_y = 300, 300
pyautogui.moveTo(start_x, start_y)
pyautogui.mouseDown()
pyautogui.dragTo(end_x, end_y)
pyautogui.mouseUp()

# 演示保存绘制的图形
pyautogui.hotkey('ctrl','s')
time.sleep(2)
file_name_input_location = pyautogui.locateCenterOnScreen('file_name_input.png')
if file_name_input_location:
pyautogui.click(file_name_input_location.x, file_name_input_location.y)
pyautogui.typewrite('drawing.png')
pyautogui.press('enter')

在这个示例中,我们首先通过图像识别找到绘图软件的图标并打开软件 。然后,找到矩形绘制工具并使用鼠标操作绘制一个矩形。最后,演示保存绘制图形的操作。在运行这段代码时,同时开启录屏软件,就可以录制出一个完整的软件使用教程视频,大大提高了制作教程的效率和准确性。

游戏辅助工具

以简单的扫雷游戏为例,我们可以使用 PyAutoGUI 制作一个辅助工具,帮助玩家自动识别雷区和点击安全区域 。以下是一个简单的实现思路和示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import pyautogui
import time
import cv2

# 定义雷区格子的大小和初始位置
cell_size = 18
left, top = 0, 0 # 假设雷区左上角坐标,实际需要根据屏幕截图识别

# 加载数字图片模板,用于识别雷区数字
number_templates = []
for i in range(1, 9):
template = cv2.imread(f'{i}.png', cv2.IMREAD_GRAYSCALE)
number_templates.append(template)


def recognize_number(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
best_match = None
best_score = 0
for i, template in enumerate(number_templates):
result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > best_score:
best_score = max_val
best_match = i + 1
return best_match


def analyze_minefield():
screenshot = pyautogui.screenshot(region=(left, top, cell_size * 30, cell_size * 16)) # 假设雷区大小为30x16
screenshot = cv2.cvtColor(numpy.array(screenshot), cv2.COLOR_RGB2BGR)
for y in range(0, 16):
for x in range(0, 30):
cell = screenshot[y * cell_size:(y + 1) * cell_size, x * cell_size:(x + 1) * cell_size]
number = recognize_number(cell)
if number:
print(f'坐标({x}, {y})处的数字为:{number}')


# 开始分析雷区
time.sleep(3) # 等待游戏界面加载完成
analyze_minefield()

在这个示例中,我们首先定义了雷区格子的大小和初始位置,然后加载数字图片模板用于识别雷区中的数字 。recognize_number函数通过模板匹配的方式识别每个格子中的数字,analyze_minefield函数则对整个雷区进行截图并分析每个格子的数字。通过这种方式,我们可以根据识别出的数字来判断哪些区域是安全的,哪些区域可能有雷,从而实现简单的扫雷游戏辅助功能。 请注意,在实际游戏中使用辅助工具可能涉及违反游戏规则的问题,仅用于技术学习和研究目的。

使用注意事项与技巧

防故障机制

PyAutoGUI 提供了自动防故障功能,默认情况下是开启的 。当鼠标移动到屏幕的左上角时,会触发FailSafeException异常,程序会停止执行,这可以防止程序出现异常情况时无法停止,导致不可预期的后果 。如果你确定自己的程序不会出现问题,或者在调试过程中不想被这个机制中断,可以通过以下方式禁用它:

1
2
3
4
import pyautogui

# 禁用自动防故障功能
pyautogui.FAILSAFE = False

不过,禁用故障保护可能会带来风险,因此请谨慎操作。 另外,为了避免操作速度过快导致程序出错或错过某些界面元素的响应,你可以设置停顿功能 。通过设置pyautogui.PAUSE变量,可以让每个 PyAutoGUI 函数调用在执行动作后暂停指定的秒数。例如,设置暂停时间为 1 秒:

1
2
3
4
import pyautogui

# 设置每次操作后暂停1秒
pyautogui.PAUSE = 1

这样,在执行诸如鼠标移动、点击、键盘输入等操作后,程序都会暂停 1 秒,给系统和其他应用程序足够的时间来响应。

坐标定位技巧

在使用 PyAutoGUI 进行鼠标操作时,准确获取屏幕坐标非常关键 。你可以使用pyautogui.position()函数来获取当前鼠标的坐标位置,返回一个包含横坐标和纵坐标的元组 。例如:

1
2
3
4
5
import pyautogui

# 获取当前鼠标坐标
x, y = pyautogui.position()
print(f'当前鼠标坐标: ({x}, {y})')

另外,在进行图像识别定位时,为了提高定位的准确性和稳定性,可以设置locateOnScreen()函数的confidence参数 。该参数表示匹配的置信度,取值范围为 0 到 1,值越高表示匹配要求越严格 。例如,将置信度设置为 0.8:

1
2
3
4
5
6
7
8
9
import pyautogui

# 在屏幕上查找图像,置信度为0.8
location = pyautogui.locateOnScreen('image.png', confidence=0.8)
if location:
left, top, width, height = location
print(f'找到图像,位置为:({left}, {top}),宽度为:{width},高度为:{height}')
else:
print('未找到图像')

当在不同分辨率的屏幕上运行自动化脚本时,由于相同的像素坐标在不同分辨率下代表的实际位置可能不同,会导致坐标不准确 。为了解决这个问题,可以使用pyautogui.size()函数获取当前屏幕的分辨率,并根据分辨率调整坐标 。例如,假设你希望在屏幕中心进行点击操作,无论屏幕分辨率如何变化,都可以这样实现:

1
2
3
4
5
6
7
8
9
import pyautogui

# 获取屏幕分辨率
screen_width, screen_height = pyautogui.size()
# 计算屏幕中心坐标
center_x = screen_width // 2
center_y = screen_height // 2
# 移动鼠标到屏幕中心并点击
pyautogui.click(center_x, center_y)

异常处理

在使用 PyAutoGUI 时,可能会遇到各种异常情况 。除了前面提到的FailSafeException异常外,还可能遇到ImageNotFoundException异常,当使用locateOnScreen()等图像识别函数找不到指定图像时会抛出该异常 。你可以使用try - except语句来捕获并处理这些异常,使程序更加健壮 。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pyautogui

try:
# 在屏幕上查找图像
location = pyautogui.locateOnScreen('icon.png')
if location:
x, y = pyautogui.center(location)
pyautogui.click(x, y)
else:
print('未找到图像')
except pyautogui.ImageNotFoundException:
print('在屏幕上未找到指定图像')
except pyautogui.FailSafeException:
print('触发自动防故障机制,程序停止')

另外,在进行键盘输入操作时,如果目标窗口没有获得焦点,可能会导致输入内容没有出现在预期的位置 。为了避免这种情况,可以在执行键盘输入操作前,使用pyautogui.click()函数先将鼠标点击到目标窗口,使其获得焦点 。例如:

1
2
3
4
5
6
7
8
import pyautogui

# 假设目标窗口的位置已知
window_x, window_y = 100, 100
# 点击目标窗口,使其获得焦点
pyautogui.click(window_x, window_y)
# 进行键盘输入操作
pyautogui.typewrite('Hello, World!')

通过合理运用这些使用注意事项与技巧,可以让你在使用 PyAutoGUI 进行自动化任务时更加得心应手,提高脚本的稳定性和可靠性 。

frp(Fast Reverse Proxy)是一款开源的高性能内网穿透代理工具,它允许你将位于NAT或防火墙后面的本地服务器暴露到公网上。frp支持TCP、UDP、HTTP和HTTPS协议,使得内部服务可以通过域名被外部访问。此外,frp还提供了P2P连接模式,进一步增强了其灵活性和可用性。

功能特点

frp以其简洁的设计和丰富的功能而闻名,以下是一些核心特性:

  1. 协议支持:支持TCP、UDP、HTTP和HTTPS协议,适用于多种网络环境。
  2. P2P连接:提供P2P连接模式,实现客户端间的直接通信,无需经过服务器。
  3. 配置灵活:支持TOML、YAML和JSON格式的配置文件,方便不同用户的需求。
  4. 安全性:支持Token和OIDC认证,增强连接的安全性。
  5. 性能优化:提供TLS加密和数据压缩,保障数据传输的安全和效率。
  6. 监控与日志:集成Prometheus监控,支持实时监控代理状态和流量。
  7. 负载均衡:支持通过分组实现简单的负载均衡。
  8. 健康检查:提供TCP和HTTP健康检查,确保服务的高可用性。
  9. 自定义域名:支持自定义子域名,方便在共享服务器上区分不同用户的服务。
  10. 插件系统:支持客户端和服务器端的插件扩展,增加了功能的灵活性和多样性。

安装

步骤1:访问GitHub Releases页面

打开浏览器,访问frp的GitHub Releases页面
在页面中,找到最新发布的版本,这通常会被标记为“Latest”或有相应的版本号。

步骤2:下载二进制文件

根据你的操作系统(Windows、Linux或macOS)和架构(如x86_64、arm等),选择相应的预编译二进制文件。

  • 对于Linux用户,你会找到以linux_amd64linux_arm64等命名的压缩文件。
  • 对于macOS用户,文件名通常包含darwin
  • 对于Windows用户,文件名会包含windows_4.0
    点击相应的文件名,下载到你的计算机上。

步骤3:解压缩文件

解压缩下载的文件。对于Linux和macOS用户,可以使用tar命令:

1
tar -zxvf frp_0.39.0_linux_amd64.tar.gz

对于Windows用户,可以使用文件资源管理器或第三方解压缩软件解压.zip文件。

步骤4:移动到合适的目录

在解压缩的目录中,你会找到frpsfrpc两个可执行文件,分别对应服务器端和客户端。

frpsfrpc移动到合适的目录,例如/usr/local/bin(需要管理员权限):

1
sudo mv frps frpc /usr/local/bin/

步骤5:检查运行

在命令行中运行frps -vfrpc -v来检查二进制文件是否正确无误:

1
2
frps -v
frpc -v

这将显示frp的版本信息,确认安装成功。

示例用法

frp的使用涉及两个主要组件:frps(服务器端)和frpc(客户端)。以下是一些基本的示例用法,帮助你快速开始使用frp。

1. 通过SSH访问内网计算机

服务端(frps)配置和启动:

  1. 在拥有公网IP的服务器上配置frps.toml
1
2
# frps.toml
bindPort = 7000
  1. 启动frps
1
./frps -c ./frps.toml

客户端(frpc)配置和启动:

  1. 在内网计算机上配置frpc.toml
1
2
3
4
5
6
7
8
9
10
# frpc.toml
serverAddr = "x.x.x.x" # 服务端公网IP
serverPort = 7000

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
  1. 启动frpc
1
./frpc -c ./frpc.toml
  1. 通过SSH访问内网计算机:
1
ssh -p 6000 用户名@服务端公网IP

2. 使用自定义域名访问内网Web服务

服务端(frps)配置和启动:

  1. 配置frps.toml
1
2
3
# frps.toml
bindPort = 7000
vhostHTTPPort = 8080
  1. 启动frps
1
./frps -c ./frps.toml

客户端(frpc)配置和启动:

  1. 配置frpc.toml
1
2
3
4
5
6
7
8
9
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.example.com"]
  1. 启动frpc
1
./frpc -c ./frpc.toml
  1. 配置域名解析:
    www.example.com的A记录指向frps服务器的公网IP。

  2. 访问Web服务:
    通过浏览器访问http://www.example.com:8080

这些示例仅展示了frp的一小部分功能。frp的灵活性和强大的功能使其成为内网穿透的有力工具。你可以根据具体需求调整配置,实现更复杂的网络穿透和代理需求。

随着 Docker 的广泛应用,越来越多的开发者和企业开始使用 Docker 来构建和部署应用。然而,由于网络原因,直接从 Docker Hub 拉取镜像可能会遇到速度慢或者不稳定的问题。为了解决这一问题,本文将介绍如何配置国内镜像源,以加速 Docker 镜像的拉取速度。

为什么需要配置国内镜像源?

直接从 Docker Hub 拉取镜像可能会受到网络限制的影响,导致速度慢或者失败。配置国内镜像源可以有效地解决这一问题,提高镜像拉取的速度和稳定性。

配置步骤

以下是配置国内 Docker 镜像源的具体步骤:

1. 创建或修改 Docker 配置文件

在 Linux 系统中,你需要修改或创建 /etc/docker/daemon.json 文件。如果文件不存在,你可以使用以下命令创建它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://doublezonline.cloud",
"https://dislabaiot.xyz",
"https://docker.fxxk.dedyn.io",
"https://dockerpull.org",
"https://docker.unsee.tech",
"https://hub.rat.dev",
"https://docker.1panel.live",
"https://docker.nastool.de",
"https://docker.zhai.cm",
"https://docker.5z5f.com",
"https://a.ussh.net",
"https://docker.udayun.com",
"https://hub.geekery.cn"
]
}
EOF

2. 重启 Docker 服务

修改配置文件后,需要重启 Docker 服务以使配置生效:

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

3. 验证配置是否成功

使用以下命令检查 Docker 信息,确认镜像源是否已经更改:

1
docker info

以上步骤可以帮助你配置国内镜像源,以加速 Docker 镜像的拉取速度。请根据实际情况选择可用的镜像源进行配置。这些镜像源均来自最新的搜索结果,确保了时效性。

在数字化时代,脚本编程在软件开发和自动化任务中扮演着至关重要的角色。然而,未加密的脚本代码面临着潜在的盗用和篡改风险,甚至可能导致敏感信息泄露。本文将探讨多种有效的脚本加密与编译技术,涵盖了Shell和Perl脚本的保护方法,旨在帮助开发者保护自己的代码和敏感信息。

Shell脚本加密与编译方法

使用shc工具

SHC(Shell Script Compiler)是一个开源工具,用于将Shell脚本编译成可执行文件。它将代码转换为C语言程序,然后再编译成二进制文件,以保护源代码。SHC的主要目的是提供一个简单的方式来保护Shell脚本代码,防止未经授权的访问和篡改。

  • SHC的功能:SHC将Shell脚本编译成二进制可执行文件,隐藏脚本的实现细节,并在编译过程中对脚本内容进行预处理和加密。

安装SHC

通过包管理器安装SHC(推荐):

1
2
3
4
5
6
# Ubuntu/Debian:
sudo apt-get install shc

# CentOS/RHEL
sudo yum install epel-release
sudo yum install shc

从源代码编译安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 安装必要的编译工具和库。包括 `gcc`(GNU C编译器)和 `make` 工具:
sudo apt-get update
sudo apt-get install build-essential

# 访问 SHC 的 GitHub 仓库,下载最新的源代码压缩包,或通过 `git` 克隆仓库。
git clone https://github.com/neurobin/shc.git
cd shc

# 编译 SHC:
make

# 安装 SHC,将编译的二进制文件移动到 `/usr/local/bin` 目录(或其他合适的目录):
sudo cp shc /usr/local/bin/

# 检查 SHC 是否安装成功:
shc -h

编译示例

脚本(hello.sh):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash

# 检查是否为root用户
if [ "$EUID" -ne 0 ]; then
echo "请以管理员权限运行此脚本(使用sudo)!"
exit 1
fi

# 显示系统信息
echo "-----------------------------"
echo "系统信息"
echo "-----------------------------"
echo "当前用户: $(whoami)"
echo "系统时间: $(date)"
echo "操作系统版本: $(lsb_release -d | cut -f2)"

# 列出当前目录文件
echo "-----------------------------"
echo "当前目录中的文件:"
ls -1

# 用户选择文件
read -p "请选择一个文件以查看其内容 (输入文件名): " file_name

# 检查文件是否存在
if [ -f "$file_name" ]; then
echo "-----------------------------"
echo "文件内容: $file_name"
cat "$file_name"

# 将输出重定向到日志文件
echo "日志保存到 log.txt"
{
echo "文件内容: $file_name"
cat "$file_name"
} > log.txt

else
echo "文件不存在!"
fi

编译脚本:

1
shc -f hello.sh

将生成两个文件:hello.sh.x(可执行文件)和hello.sh.x.c(C源文件)。

执行编译文件:

1
./hello.sh.x

加密与编码

除了使用shc工具,还可以使用base64编码或openssl加密来增加脚本的安全性。

使用base64编码将脚本内容进行base64编码,并在运行时解码执行:

1
2
3
4
5
# 编码
base64 hello.sh > hello_base64.txt

# 解码并执行
base64 -d hello_base64.txt | bash

使用openssl工具对脚本进行对称或非对称加密,然后在运行时解密。例如:

1
2
3
4
5
# 加密
openssl aes-256-cbc -salt -in hello.sh -out hello.sh.enc

# 解密并执行
openssl aes-256-cbc -d -in hello.sh.enc | bash

Perl脚本加密与编译方法

PAR::Packer工具

PAR::Packer是一个Perl模块,用于将Perl脚本及其所有依赖打包成可执行的二进制文件。它分析Perl脚本,自动识别所用到的模块,并将这些模块打包在内,确保在目标环境中运行时可以找到。

  • 安装并使用
1
2
3
4
5
# 以使用 CPAN 安装:
cpan PAR::Packer

# 打包Perl脚本
pp -o hello.pxf hello.pl

perlcc编译器

perlcc是Perl语言的一个编译器,它可以将Perl脚本编译成C代码,然后进一步编译成可执行的二进制文件。然而,perlcc可能无法处理某些复杂的Perl特性或者特定模块,导致编译失败。

  • 编译过程示例
1
perlcc -o task_manager task_manager.pl

使用-d选项可以在编译时显示调试信息:

1
perlcc -d -o hello hello.pl

查看perlcc的更多选项和功能,可以使用以下命令:

1
perlcc -h

加密与解密技术

使用Crypt::CBC模块可以实现对数据的加密和解密。Crypt::CBC提供了基于块密码的加密和模式,常用的加密算法包括AES、DES等。

  • 安装Crypt::CBC
1
cpan Crypt::CBC

使用Crypt::CBC模块加密一个Perl脚本,涉及到定义一个加密的过程并将脚本本身保存为一个密文,然后可以在运行时解密并执行。这种做法只是为了保护源代码,这并不是一种绝对的安全措施,因为熟悉Perl的人仍然可以通过逆向工程等手段获取原始代码。

以下是使用Crypt::CBC加密和解密Perl脚本的示例代码:

加密脚本(encrypt_script.pl):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl
use strict;
use warnings;
use Crypt::CBC;
use MIME::Base64;
use File::Slurp;

# 配置加密参数
my $key = '*********'; # 选择一个合适的密钥
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Crypt::AES',
);

# 读取原始脚本
my $script = read_file('task_manager.pl');

# 加密脚本
my $ciphertext = $cipher->encrypt_hex($script);
write_file('hello_encrypted.pl', $ciphertext);

print "Script encrypted and saved to hello_encrypted.pl\n";

解密并执行脚本(run_encrypted.pl):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/perl
use strict;
use warnings;
use Crypt::CBC;
use MIME::Base64;
use File::Slurp;

# 配置加密参数
my $key = '******'; # 确保与加密时的密钥一致
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Crypt::AES',
);

# 读取加密脚本
my $ciphertext = read_file('hello_encrypted.pl');

# 解密
my $decrypted = $cipher->decrypt_hex($ciphertext);

# 执行解密后的脚本
eval $decrypted;
if ($@) {
die "Error executing decrypted script: $@";
}

运行解密并执行的脚本:

1
perl run_encrypted.pl

总结

脚本加密和编译技术为确保源代码安全性提供了有效的手段。本文详细介绍了使用流行工具和方法对Shell脚本和Perl脚本进行加密和编译的步骤,旨在帮助开发者保护自己的代码和敏感信息。

Pake 是一个基于 Rust 的工具,它允许开发者轻松构建轻量级的多平台桌面应用。以其小巧的体积和卓越的性能,Pake 成为了许多开发者的首选工具。本文将详细介绍 Pake 的特性、安装方法、使用指南以及如何进行定制开发,并特别强调快捷键的使用。

Pake 的特性

Pake 的核心特性包括:

  • 体积小:相比传统的 Electron 套壳打包,Pake 的体积小将近 20 倍,大约在 5M 左右。
  • 性能优异:Pake 的底层使用的是 Rust Tauri 框架,相较于 JavaScript 框架,它提供了更轻快的性能体验和更小的内存占用。
  • 功能丰富:Pake 不仅能打包应用,还实现了快捷键透传、沉浸式窗口、拖动、样式改写、去广告等功能,并支持产品的极简风格定制。
  • 简单易用:Pake 被描述为一个简单的小玩具,使用 Tauri 替代了传统的套壳网页打包思路,同时推荐使用 PWA(Progressive Web Apps)。

开始使用 Pake

安装 Pake CLI

Pake 提供了命令行工具,可以通过 npm 进行安装:

1
npm install -g pake-cli

命令行一键打包

使用 Pake 进行一键打包非常简单,以下是基本的命令使用示例:

1
pake url [OPTIONS]...

例如,如果你想打包 Weekly 应用,并隐藏标题栏,可以使用以下命令:

1
pake https://weekly.tw93.fun --name Weekly --hide-title-bar

快捷键说明

Pake 支持快捷键,以提高用户的工作效率。以下是 Pake 支持的快捷键及其功能:

Mac Windows/Linux 功能
⌘ + [ Ctrl + ← 返回上一个页面
⌘ + ] Ctrl + → 去下一个页面
⌘ + ↑ Ctrl + ↑ 自动滚动到页面顶部
⌘ + ↓ Ctrl + ↓ 自动滚动到页面底部
⌘ + r Ctrl + r 刷新页面
⌘ + w Ctrl + w 隐藏窗口,非退出
⌘ + - Ctrl + - 缩小页面
⌘ + + Ctrl + + 放大页面
⌘ + = Ctrl + = 放大页面
⌘ + 0 Ctrl + 0 重置页面缩放

高级使用

Pake 的代码结构和高级用法可以在其官方文档中找到。以下是一些关键点:

  • 修改 src-tauri 目录下的 pake.json 中的 url 和 productName 字段,并同步修改 tauri.config.json 中的 domain 字段。
  • 修改 tauri.xxx.conf.json 中的 icon 和 identifier 字段,图标可以从 icons 目录选择,或者从 macOSicons 下载。
  • 在 pake.json 中修改窗口属性,如 width/height、fullscreen、resizable 等。
  • 适配 Mac 沉浸式头部,可以将 hideTitleBar 设置为 true,并为 Header 元素添加 padding-top 样式。

结语

Pake 是一个强大的工具,它让构建轻量级多端桌面应用变得简单快捷。无论是小白用户、开发用户还是折腾用户,都能在 Pake 中找到适合自己的使用方式。希望这篇文章能帮助你更好地了解和使用 Pake,享受构建桌面应用的乐趣。

0%