如何用PHP/Python/Node.js编写模拟CLI交互的无头脚本?
当然可以,这三门语言都有成熟的工具/库能实现类似expect的功能,通过模拟**伪终端(PTY)**环境,完全复刻手动敲击键盘的交互逻辑,还能捕获所有终端输出——哪怕目标进程启动了独立子进程、绕过了标准stdin/stdout流,完全不需要依赖窗口定位的宏工具。
Python
Python的pexpect是最直接的替代方案,完全对标expect,专门用于CLI交互场景,基于伪终端实现,能捕获所有终端输出。
示例代码:
import pexpect # 启动目标CLI进程,模拟真实终端环境 child = pexpect.spawn("your_target_cli") # 匹配登录提示符并输入用户名 child.expect("Username: ") child.sendline("your_username") # 匹配密码提示符并输入密码 child.expect("Password: ") child.sendline("your_password") # 捕获命令执行后的全部输出 child.expect(pexpect.EOF) print(child.before.decode("utf-8"))
它会接管进程的伪终端,所以不管进程是否绕开标准流,只要是终端上显示的内容都能被捕获,和手动操作完全一致。
Node.js
Node.js可以用node-expect(注意区分断言库expect.js)或node-pty实现,前者封装了交互逻辑,后者提供底层伪终端能力,适合复杂场景。
用node-expect的示例:
const expect = require("expect"); // 启动目标CLI进程 const child = expect.spawn("your_target_cli"); // 链式处理交互流程 child.expect("Username: ", () => { child.send("your_username\n"); child.expect("Password: ", () => { child.send("your_password\n"); child.expect(expect.EOF, () => { console.log(child.stdout.toString()); }); }); });
如果需要更高灵活性,直接用node-pty创建伪终端,自己处理输入输出的匹配逻辑即可,同样能捕获所有终端输出。
PHP
PHP可以通过php-expect扩展实现(需通过PECL安装),或者用proc_open配合伪终端手动实现(无需扩展,但代码量稍大)。
用php-expect的示例:
// 启动目标CLI进程 $exp = expect_popen("your_target_cli"); // 匹配用户名提示符并发送内容 expect_expectl($exp, [ ["Username: ", "send", "your_username\n"] ]); // 匹配密码提示符并发送内容 expect_expectl($exp, [ ["Password: ", "send", "your_password\n"] ]); // 读取所有输出 $output = expect_read($exp); echo $output; // 关闭进程 fclose($exp);
如果不想安装扩展,可通过打开/dev/ptmx(Linux)创建伪终端,再用proc_open将进程绑定到该终端,手动处理读写和匹配逻辑,同样能实现需求。
核心原理
这些方案都是基于**伪终端(PTY)**实现的,会给目标进程创建一个和真实终端完全一致的交互环境,进程会认为是用户在手动操作,因此所有输出(包括绕开标准流的内容)都会输出到伪终端中,脚本可以直接捕获,完全不需要依赖窗口定位、鼠标复制等宏操作,逻辑和无头浏览器模拟网页交互类似。
内容的提问来源于stack exchange,提问作者Dustin Soodak

