AWS Lambda中Node.js包装PHP调用Python脚本遇OSError错误求助
解决AWS Lambda中PHP调用Python脚本执行ffprobe时的"OSError: No such file or directory"问题
我之前在Lambda环境里做跨语言调用的时候也踩过类似的路径和依赖坑,给你几个关键的排查方向和解决办法:
1. 先确认所有文件的实际路径是否正确
Lambda的执行环境目录结构和本地完全不一样,别想当然用本地的路径:
- 先在PHP里加一行调试代码,打印出
__DIR__的实际值:
然后去Lambda的CloudWatch日志里看这个路径,确认error_log("PHP script directory: " . __DIR__);ffprobe_hosts.py确实在这个目录下。 - 关于
ffprobe:Lambda默认的运行时(不管是Node.js还是PHP的基础镜像)都不带ffmpeg/ffprobe工具!你要么把ffprobe二进制文件打包到你的部署包里,要么用Lambda层来挂载这个工具。如果是打包到部署包,那Python里的路径不能写/usr/bin/ffprobe,得换成你实际放置的路径,比如os.path.join(os.path.dirname(__file__), 'ffprobe')。
2. 修复Python中subprocess的调用方式
你现在的命令拼接方式容易出问题,尤其是当src_video是带特殊字符的URL时,而且路径如果有空格也会报错。建议改成参数列表的方式,同时对URL做转义:
import subprocess import shlex import os # 先确认ffprobe的实际路径,比如和脚本同目录的话 ffprobe_path = os.path.join(os.path.dirname(__file__), "ffprobe") # 转义视频URL,避免特殊字符破坏命令结构 escaped_video = shlex.quote(src_video) cmd = [ ffprobe_path, "-show_frames", "-of", "compact=p=0", "-f", "lavfi", f"movie={escaped_video},select=gt(scene,{str(threshold)})" ] # 执行命令 scene_ps = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
3. 检查文件权限和Python解释器路径
- 确保你的
ffprobe_hosts.py和ffprobe都有可执行权限:在本地打包前,执行chmod +x ffprobe_hosts.py和chmod +x ffprobe,再打包成zip上传到Lambda。 - 如果你在PHP里直接调用Python脚本(没指定解释器),那脚本开头的shebang行必须正确,比如
#!/usr/bin/env python3(Lambda里的Python3路径一般是这个)。或者你可以在PHP的shell_exec里明确指定Python解释器路径:
这里顺便用$output = shell_exec('/usr/bin/python3 ' . escapeshellarg(__DIR__ . "/ffprobe_hosts.py") . ' ' . escapeshellarg($video_url) . " 2>&1");escapeshellarg()转义了$video_url,避免URL里的特殊字符破坏shell命令。
4. 用日志定位具体错误
Lambda的日志是排查问题的关键,建议把所有输出都记录下来:
- 在PHP里,把shell_exec的标准错误也捕获到:
$command = '/usr/bin/python3 ' . escapeshellarg(__DIR__ . "/ffprobe_hosts.py") . ' ' . escapeshellarg($video_url); $output = shell_exec($command . " 2>&1"); error_log("Command output: " . $output); - 在Python脚本开头加调试代码,确认路径和文件存在:
这些信息会出现在CloudWatch日志里,能帮你快速定位是找不到脚本、找不到ffprobe,还是其他权限问题。import os print(f"Python script path: {__file__}") ffprobe_path = os.path.join(os.path.dirname(__file__), "ffprobe") print(f"ffprobe exists: {os.path.exists(ffprobe_path)}") print(f"ffprobe is executable: {os.access(ffprobe_path, os.X_OK)}")
内容的提问来源于stack exchange,提问作者Nithin C
相关产品推荐
相关产品推荐

