嵌入式 ARM 设备交叉编译 mosquitto 2.0.20 (完整 TLS 支持) 详细教程 TRAE全程辅助,没敲一行代码

嵌入式 ARM 设备交叉编译 mosquitto 2.0.20 (完整 TLS 支持) 详细教程,TRAE全程辅助,没敲一行代码

本文记录了在 ARM 嵌入式设备上交叉编译 mosquitto 2.0.20 并启用 TLS 支持的完整过程,包括从下载、编译、部署到调试验证的每一步操作,以及遇到的所有问题和解决方案。其中全程是TRAE辅助编程实现,我发命令,发log,后来卡在8883端口不通,加我的经验判断应该是TLS版本问题,给TRAE仙人指路,最后数据通了!!~

目录

  1. 问题背景
  2. 环境说明
  3. [交叉编译 OpenSSL](#交叉编译 OpenSSL)
  4. [交叉编译 mosquitto](#交叉编译 mosquitto)
  5. 部署到开发板
  6. 问题排查与解决
  7. 最终验证
  8. 总结

1. 问题背景

1.1 项目需求

在嵌入式 TCU 设备上通过 Quectel EC20 4G 模块连接 MQTT Broker(EMQX),实现消息订阅功能。

1.2 初始问题

用户原有环境:

  • mosquitto_sub 版本:2.0.10(不支持 TLS 选项)
  • libmosquitto.so.1 版本:2.0.10

用户遇到的原始错误:

复制代码
Error: Unknown option '--cafile'.
Use 'mosquitto_sub --help' to see usage.

1.3 目标

  1. 交叉编译 mosquitto 2.0.20 客户端(支持 TLS)
  2. 正确链接 OpenSSL 库
  3. 成功连接 EMQX Broker (端口 8883, mqtts://)

2. 环境说明

2.1 开发环境

项目 路径/值
开发主机 x86_64 Linux
交叉编译器 /opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin/
编译器前缀 arm-cortex_a8-linux-gnueabi-
GCC 版本 4.7.3

2.2 目标环境

项目 说明
目标设备 TCU (嵌入式 ARM Cortex-A8)
4G 模块 Quectel EC20
系统 嵌入式 Linux (Buildroot)

2.3 软件版本

软件 版本 存放位置
OpenSSL 1.1.1w /tmp/openssl-1.1.1w → /tmp/openssl-arm
mosquitto 2.0.20 /tmp/mosquitto-2.0.20

3. 交叉编译 OpenSSL 1.1.1w

3.1 下载并解压

命令:

bash 复制代码
cd /tmp
wget https://github.com/openssl/openssl/releases/download/OpenSSL_1_1_1w/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz

预期输出:

复制代码
--2026-04-10 09:30:15--  https://github.com/openssl/openssl/releases/download/OpenSSL_1_1_1w/openssl-1.1.1w.tar.gz
...
openssl-1.1.1w.tar.gz        100%[===================>]  9.8MB   890KB/s    用时 11s

2026-04-10 09:30:26 (890 KB/s) - 已保存 "openssl-1.1.1w.tar.gz" [10289152/10289152]

为什么这样做:

  • OpenSSL 是 TLS 加密的基础库
  • 必须使用 /tmp 目录(项目目录可能只读)
  • 选择 1.1.1w 稳定版( LTS 版本)

3.2 配置编译环境

命令:

bash 复制代码
cd /tmp/openssl-1.1.1w
export PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH
./Configure linux-armv4 --prefix=/tmp/openssl-arm shared

预期输出:

复制代码
Operating system: linux-armv4
Configuring OpenSSL distribution for linux-armv4
If it fails, try a different target operating system, e.g. linux-generic32
Configured for linux-armv4

为什么用 linux-armv4:

  • 必须指定 ARM 架构,不能用默认的 x86_64
  • linux-armv4 适用于 ARMv4 及以上架构

3.3 编译 OpenSSL

命令:

bash 复制代码
make -j4

预期输出(最后几行):

复制代码
cc -O4 -fPIC ... -c ssl/ssl_lib.c -o ssl/ssl_lib.o
ar  rcs libcrypto.a ...
ld -shared -soname libssl.so.1.1 -o libssl.so.1.1 ...

编译时间: 约 5-10 分钟(取决于 CPU)

3.4 安装 OpenSSL

命令:

bash 复制代码
make install_sw

预期输出(最后几行):

复制代码
install prefix: /tmp/openssl-arm
...
libcrypto.a -> /tmp/openssl-arm/lib/libcrypto.a
libssl.so.1.1 -> /tmp/openssl-arm/lib/libssl.so.1.1
libcrypto.so.1.1 -> /tmp/openssl-arm/lib/libcrypto.so.1.1

为什么用 install_sw:

  • 只安装软件库和头文件
  • 不安装文档和 man pages,减少安装体积

3.5 创建符号链接

问题: 安装后只有 libssl.so.1.1(带版本号),编译链接时需要 libssl.so(不带版本号)

命令:

bash 复制代码
cd /tmp/openssl-arm/lib
ln -sf libssl.so.1.1 libssl.so
ln -sf libcrypto.so.1.1 libcrypto.so

验证:

bash 复制代码
ls -la /tmp/openssl-arm/lib/

预期输出:

复制代码
lrwxrwxrwx libssl.so -> libssl.so.1.1
-rwxrwxrwx libssl.so.1.1  556017 Apr 10 09:45 libssl.so.1.1
lrwxrwxrwx libcrypto.so -> libcrypto.so.1.1
-rwxrwxrwx libcrypto.so.1.1 2641145 Apr 10 09:45 libcrypto.so.1.1

3.6 验证 OpenSSL 架构

命令:

bash 复制代码
file /tmp/openssl-arm/lib/libssl.so.1.1

预期输出:

复制代码
libssl.so.1.1: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, with debug_info, not stripped

重要: 必须显示 ARM 架构,不能是 x86_64!


4. 交叉编译 mosquitto 2.0.20

4.1 下载 mosquitto

命令:

bash 复制代码
cd /tmp
wget https://mosquitto.org/files/source/mosquitto-2.0.20.tar.gz
tar -xzf mosquitto-2.0.20.tar.gz

预期输出:

复制代码
--2026-04-10 10:00:00--  https://mosquitto.org/files/source/mosquitto-2.0.20.tar.gz
...
mosquitto-2.0.20/CMakeLists.txt
mosquitto-2.0.20/Makefile
mosquitto-2.0.20/client/
mosquitto-2.0.20/lib/
...

4.2 清理之前的编译

命令:

bash 复制代码
cd /tmp/mosquitto-2.0.20
make -C lib clean
make -C client clean

预期输出:

复制代码
make: 进入目录"/tmp/mosquitto-2.0.20/lib"
rm -f *.o libmosquitto.so.1 ...
make: 离开目录"/tmp/mosquitto-2.0.20/lib"

4.3 第一次编译尝试(失败的尝试)

命令:

bash 复制代码
PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH \
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- \
make -C lib WITH_TLS=yes WITH_CJSON=no WITH_SSL=/tmp/openssl-arm \
CFLAGS="-I/tmp/openssl-arm/include" \
LDFLAGS="-L/tmp/openssl-arm/lib" \
LIBS="-lssl -lcrypto"

预期输出:

复制代码
arm-cortex_a8-linux-gnueabi-cc -shared ... -o libmosquitto.so.1 -lrt -lssl -lcrypto

编译成功,但后来发现问题:

在开发板上运行时出现:

复制代码
Error: Problem setting TLS options: This feature is not supported.

4.4 问题排查(开发板上报错)

命令(开发板):

bash 复制代码
strings /tmp/mosquitto-2.0.20/lib/libmosquitto.so.1 | grep -E "libssl|libcrypto"

预期输出:(空,说明没有链接 OpenSSL)

命令(开发电脑):

bash 复制代码
readelf -d /tmp/mosquitto-2.0.20/lib/libmosquitto.so.1 | grep NEEDED

实际输出(发现问题):

复制代码
0x00000001 (NEEDED)                     Shared library: [librt.so.1]
0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
0x00000001 (NEEDED)                     Shared library: [libc.so.6]

问题原因: libmosquitto.so.1 没有链接 libssl.solibcrypto.so

4.5 第二次编译尝试(解决链接问题)

关键发现: 必须使用完整路径指定 OpenSSL 库!

命令:

bash 复制代码
cd /tmp/mosquitto-2.0.20
make -C lib clean

PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH \
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- \
make -C lib WITH_TLS=yes WITH_CJSON=no WITH_SSL=/tmp/openssl-arm \
CFLAGS="-I/tmp/openssl-arm/include" \
LDFLAGS="-L/tmp/openssl-arm/lib" \
LIBS="/tmp/openssl-arm/lib/libssl.so.1.1 /tmp/openssl-arm/lib/libcrypto.so.1.1"

预期输出:

复制代码
arm-cortex_a8-linux-gnueabi-cc -shared -L/tmp/openssl-arm/lib ... -o libmosquitto.so.1 -lrt -lssl -lcrypto
make: 离开目录"/tmp/mosquitto-2.0.20/lib"

4.6 验证 libmosquitto.so.1 链接

命令:

bash 复制代码
readelf -d /tmp/mosquitto-2.0.20/lib/libmosquitto.so.1 | grep NEEDED

预期输出(现在包含 libssl 和 libcrypto):

复制代码
0x00000001 (NEEDED)                     Shared library: [librt.so.1]
0x00000001 (NEEDED)                     Shared library: [libssl.so.1.1]
0x00000001 (NEEDED)                     Shared library: [libcrypto.so.1.1]
0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
0x00000001 (NEEDED)                     Shared library: [libc.so.6]

4.7 编译 mosquitto_sub 客户端

命令:

bash 复制代码
make -C client clean

PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH \
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- \
make -C client WITH_TLS=yes WITH_CJSON=no WITH_SSL=/tmp/openssl-arm \
CFLAGS="-I/tmp/openssl-arm/include" \
LDFLAGS="-L/tmp/openssl-arm/lib -Wl,-rpath-link,/tmp/openssl-arm/lib" \
LIBS="/tmp/openssl-arm/lib/libssl.so.1.1 /tmp/openssl-arm/lib/libcrypto.so.1.1"

预期输出:

复制代码
arm-cortex_a8-linux-gnueabi-cc ... -o mosquitto_pub
arm-cortex_a8-linux-gnueabi-cc ... -o mosquitto_sub
make: 离开目录"/tmp/mosquitto-2.0.20/client"

4.8 验证 mosquitto_sub 支持 --cafile

命令:

bash 复制代码
strings /tmp/mosquitto-2.0.20/client/mosquitto_sub | grep -E "cafile|--ca"

预期输出:

复制代码
--cafile : path to a file containing trusted CA certificates to enable encrypted
--capath : path to a directory containing trusted CA certificates
Error: Only one of --psk or --cafile/--capath may be used at once.

4.9 复制到项目目录

命令:

bash 复制代码
# 复制客户端
cp /tmp/mosquitto-2.0.20/client/mosquitto_pub \
   /tmp/mosquitto-2.0.20/client/mosquitto_sub \
   /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/

# 复制 libmosquitto 库
cp /tmp/mosquitto-2.0.20/lib/libmosquitto.so.1 \
   /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/

# 确认文件
ls -la /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/mosquitto_sub

预期输出:

复制代码
-rwxrwxr-x 1 dcuser dcuser 71679 Apr 10 18:31 mosquitto_sub

5. 部署到开发板

5.1 部署文件清单

在开发电脑上执行(假设板子挂载在 /mnt/nandflash):

bash 复制代码
# 1. 复制 mosquitto 客户端
cp /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/mosquitto_sub /mnt/nandflash/sbin/mqtt/
cp /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/mosquitto_pub /mnt/nandflash/sbin/mqtt/

# 2. 复制 libmosquitto 库
cp /home/dcuser/work/cartech_120_DOUB_NET/cartech_120/CSCU_A1_GIT/FileReleaseFiles/nandflash/sbin/mqtt/libmosquitto.so.1 /mnt/nandflash/sbin/mqtt/

# 3. 复制 OpenSSL 库(如果板子没有)
cp /tmp/openssl-arm/lib/libssl.so.1.1 /mnt/nandflash/sbin/mqtt/lib/
cp /tmp/openssl-arm/lib/libcrypto.so.1.1 /mnt/nandflash/sbin/mqtt/lib/

# 4. 创建符号链接
cd /mnt/nandflash/sbin/mqtt/lib
ln -sf libssl.so.1.1 libssl.so
ln -sf libcrypto.so.1.1 libcrypto.so

# 5. 设置权限
chmod 755 /mnt/nandflash/sbin/mqtt/mosquitto_sub
chmod 755 /mnt/nandflash/sbin/mqtt/mosquitto_pub
chmod 755 /mnt/nandflash/sbin/mqtt/libmosquitto.so.1
chmod 755 /mnt/nandflash/sbin/mqtt/lib/*.so*

5.2 部署后验证

命令(开发板):

bash 复制代码
export LD_LIBRARY_PATH=/mnt/nandflash/sbin/mqtt:/mnt/nandflash/sbin/mqtt/lib:$LD_LIBRARY_PATH
/mnt/nandflash/sbin/mqtt/mosquitto_sub --version

预期输出:

复制代码
mosquitto_sub version 2.0.20 running on libmosquitto 2.0.20.

可能遇到的问题:

如果出现:

复制代码
mosquitto_sub version 2.0.20 running on libmosquitto 2.0.10.

说明系统找到的是旧版 libmosquitto.so.1(旧版在 /mnt/nandflash/lib/)

解决:

bash 复制代码
mv /mnt/nandflash/lib/libmosquitto.so.1 /mnt/nandflash/lib/libmosquitto.so.1.old

6. 问题排查与解决

6.1 问题一:Error: Unknown option '--cafile'

报错位置: 开发板 mqtt_receive.log

错误内容:

复制代码
Error: Unknown option '--cafile'.
Use 'mosquitto_sub --help' to see usage.

原因分析:

  • mosquitto_sub 版本太旧(2.0.10),不支持 TLS 选项
  • 或 libmosquitto.so.1 链接错误

解决:

  1. 部署新编译的 mosquitto_sub (2.0.20)
  2. 确保 LD_LIBRARY_PATH 指向正确的库目录

6.2 问题二:Error: Problem setting TLS options

报错位置: 开发板 mqtt_receive.log

错误内容:

复制代码
Error: Problem setting TLS options: This feature is not supported.

原因分析:

  • libmosquitto.so.1 没有正确链接 OpenSSL
  • readelf -d libmosquitto.so.1 | grep NEEDED 不包含 libssl.solibcrypto.so

解决:

  1. 在开发电脑上重新编译 libmosquitto.so.1
  2. 使用完整路径指定 OpenSSL 库:
bash 复制代码
LIBS="/tmp/openssl-arm/lib/libssl.so.1.1 /tmp/openssl-arm/lib/libcrypto.so.1.1"

6.3 问题三:连接超时(卡住无输出)

报错位置: 开发板 - 命令一直卡住

原因分析:

尝试多个端口测试:

端口 结果 说明
8883 卡住 TLS 端口
8083 卡住 WebSocket 端口
80 卡住 HTTP 端口
443 卡住 HTTPS 端口
1883 卡住 明文 MQTT 端口

但 ping 和 DNS 都正常,说明:

  1. 网络是通的
  2. 但 TCP 连接被拦截

这里TRAE一直认为是运营商禁用了端口,不过根据我的经验应该是TLS版本问题,最后我强行介入,让TRAE给我换TLS版本,最后通了!!~

最终发现:

手动测试时发现:

bash 复制代码
mosquitto_sub ... --tls-version tlsv1.2 -v

加上 -v 参数后能连接成功!

真正原因:

  • mosquitto_sub 默认尝试 TLS 1.3
  • EMQX 服务器只支持 TLS 1.2
  • TLS 握手失败导致看起来像连接超时

解决:

添加 --tls-version tlsv1.2 参数


6.4 问题四:nohup 后台运行进程未启动

报错位置: mqtt_subscribe.log

错误内容:

复制代码
mosquitto_sub进程未运行
错误: mosquitto_sub进程未正常启动

原因分析:

  1. LD_LIBRARY_PATH 没有正确设置
  2. 输出重定向问题

解决:

在命令中显式设置环境变量:

bash 复制代码
LOG_CMD="export LD_LIBRARY_PATH=/mnt/nandflash/sbin/mqtt:/mnt/nandflash/sbin/mqtt/lib:\$LD_LIBRARY_PATH && cd /mnt/nandflash && $CMD > $MQTT_RECEIVE_LOG 2>&1"

7. 最终验证

7.1 测试 TLS 1.2 连接

命令(开发板):

bash 复制代码
export LD_LIBRARY_PATH=/mnt/nandflash/sbin/mqtt:/mnt/nandflash/sbin/mqtt/lib:$LD_LIBRARY_PATH
/mnt/nandflash/sbin/mqtt/mosquitto_sub -h ue083e07.ala.cn-hangzhou.emqxsl.cn -p 8883 -t test -i tcu_tls12 --cafile /mnt/nandflash/sbin/mqtt/emqxsl-ca.crt -u DC120 -P DC120 --tls-version tlsv1.2 -v

预期输出:

复制代码
Client tcu_tls12 sending CONNECT
Client tcu_tls12 received CONNACK
Client tcu_tls12 sending SUBSCRIBE (Mid: 1, Topic: test, QoS: 0)

7.2 运行完整脚本

命令(开发板):

bash 复制代码
/mnt/nandflash/sbin/mqtt/mqtt_subscribe.sh

mqtt_subscribe.log 输出:

复制代码
[2026-04-10 19:07:37] ================================================
[2026-04-10 19:07:37] MQTT订阅脚本启动
[2026-04-10 19:07:37] 脚本版本: 202604101900
[2026-04-10 19:07:37] ================================================
[2026-04-10 19:07:37] 检测到TLS连接,添加证书选项
[2026-04-10 19:07:40] 构建mosquitto_sub命令: ... --tls-version tlsv1.2 ...
[2026-04-10 19:07:42] mosquitto_sub进程已运行,PID: 24415
[2026-04-10 19:07:42] ========== MQTT订阅启动成功 ==========

7.3 MQTTX 测试

在开发电脑 MQTTX 上向 topic test 发送消息,开发板上的 mqtt_receive.log 应该能收到数据。


8. 总结

8.1 完整编译命令汇总

bash 复制代码
# ==================== 1. 交叉编译 OpenSSL ====================
cd /tmp/openssl-1.1.1w
export PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH
./Configure linux-armv4 --prefix=/tmp/openssl-arm shared
make -j4 && make install_sw
cd /tmp/openssl-arm/lib
ln -sf libssl.so.1.1 libssl.so
ln -sf libcrypto.so.1.1 libcrypto.so

# ==================== 2. 交叉编译 mosquitto ====================
cd /tmp/mosquitto-2.0.20
make -C lib clean && make -C client clean

# 编译 libmosquitto(关键:用完整路径链接 OpenSSL)
PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH \
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- \
make -C lib WITH_TLS=yes WITH_CJSON=no WITH_SSL=/tmp/openssl-arm \
CFLAGS="-I/tmp/openssl-arm/include" \
LDFLAGS="-L/tmp/openssl-arm/lib" \
LIBS="/tmp/openssl-arm/lib/libssl.so.1.1 /tmp/openssl-arm/lib/libcrypto.so.1.1"

# 编译客户端
PATH=/opt/arm-cortex_a8-linux-gnueabi-4.7.3/bin:$PATH \
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- \
make -C client WITH_TLS=yes WITH_CJSON=no WITH_SSL=/tmp/openssl-arm \
CFLAGS="-I/tmp/openssl-arm/include" \
LDFLAGS="-L/tmp/openssl-arm/lib -Wl,-rpath-link,/tmp/openssl-arm/lib" \
LIBS="/tmp/openssl-arm/lib/libssl.so.1.1 /tmp/openssl-arm/lib/libcrypto.so.1.1"

# ==================== 3. 验证编译结果 ====================
# 检查架构
file /tmp/mosquitto-2.0.20/client/mosquitto_sub
# 应输出: ELF 32-bit LSB executable, ARM

# 检查动态链接
readelf -d /tmp/mosquitto-2.0.20/lib/libmosquitto.so.1 | grep NEEDED
# 应包含: libssl.so.1.1 和 libcrypto.so.1.1

# 检查 --cafile 选项
strings /tmp/mosquitto-2.0.20/client/mosquitto_sub | grep cafile
# 应输出: --cafile : path to a file containing...

8.2 关键要点

要点 说明
交叉编译器 必须使用 ARM 交叉编译器,不能用主机的 x86 gcc
OpenSSL 架构 必须确认是 ARM 架构:file libssl.so.1.1
库链接验证 用 `readelf -d libmosquitto.so.1
TLS 版本 EMQX 可能只支持 TLS 1.2,需加 --tls-version tlsv1.2
LD_LIBRARY_PATH 运行时必须设置,指向包含正确 .so 文件的目录

8.3 常见错误对照表

错误信息 报错位置 原因 解决方法
Error: Unknown option '--cafile' 开发板 mosquitto 版本太旧 部署新编译的 2.0.20
undefined reference to SSL_* 开发电脑 未链接 OpenSSL 添加 LIBS=".../libssl.so.1.1 ..."
Error: Problem setting TLS options 开发板 libmosquitto.so.1 未链接 OpenSSL 重新编译并验证 readelf -d
连接超时/卡住 开发板 TLS 版本不兼容 添加 --tls-version tlsv1.2
no version information available 开发板 链接了旧版 libmosquitto 设置正确的 LD_LIBRARY_PATH

本文详细记录了嵌入式 MQTT 客户端交叉编译全过程,包括所有遇到的问题和解决方案。

相关推荐
怕浪猫2 小时前
第11章 内存机制:让模型记住对话历史(LangChain实战)
langchain·aigc·ai编程
特立独行的猫a2 小时前
HarmonyOS 鸿蒙PC端 Qt 应用开发:第三方 Qt 开源软件移植指南
qt·harmonyos·鸿蒙·鸿蒙pc
左手厨刀右手茼蒿12 小时前
Linux 内核中的块设备驱动:从原理到实践
linux·嵌入式·系统内核
左手厨刀右手茼蒿12 小时前
Linux 内核中的模块机制:从加载到卸载
linux·嵌入式·系统内核
C++ 老炮儿的技术栈12 小时前
GCC编译时无法向/tmp 目录写入临时汇编文件,因为设备空间不足,解决
linux·运维·开发语言·汇编·c++·git·qt
大强同学12 小时前
对比 VS Code:Zed 编辑器编码体验全面解析
人工智能·windows·编辑器·ai编程
小村儿14 小时前
连载04-最重要的Skill---一起吃透 Claude Code,告别 AI coding 迷茫
前端·后端·ai编程
番茄灭世神15 小时前
MCU开发常见软件BUG总结(持续更新)
c语言·stm32·单片机·嵌入式·gd32
北冥有羽Victoria15 小时前
OpenCLI 操作网页 从0到1完整实操指南
vscode·爬虫·python·github·api·ai编程·opencli