Windows内网运维中,老OA、财务、社保、网银系统常依赖IE6/IE8的ActiveXObject、BHO、OBJECT标签和VBScript,Chrome或Edge直接打不开。给业务同事一个双击EXE,自动用IE或Edge IE模式打开固定内网地址,是常见需求。适用环境:Windows 7/10/11 + Python 3.7+ + PyInstaller 6.x。
方案选择上,webbrowser标准库三行可开,但无法传-k、-private等参数,找不到IE时会静默退回默认浏览器,跨机器容易变成Chrome;os.startfile完全跟随默认浏览器;ctypes加ShellExecute可用但参数拼接易错;Selenium IEDriver适合自动化测试,不适合做启动器。正式交付推荐subprocess直接调用iexplore.exe,保留全部命令行参数且无第三方依赖。核心是别用webbrowser.open()兜底。
环境准备:python -m venv .venv;.venv\Scripts\activate;pip install pyinstaller。Python 3.10/3.11较稳,3.12需PyInstaller>=6.0,3.13部分hook未跟上;打包架构尽量与目标机一致,64位Win10用64位Python打包。独立虚拟环境能减小打包体积。
定位IE不要硬编码。环境变量优先加常见路径兜底。64位Windows有Program Files下64位IE和Program Files(x86)下32位IE;老ActiveX插件常只有32位,实践中优先32位成功率更高,可对调环境变量顺序。读取版本时Win10的Version常年9.11.x,真实版本看svcVersion,如11.0.19041.0。
- import os
- from pathlib import Path
- def find_ie():
- cands = []
- for var in ('ProgramFiles', 'ProgramFiles(x86)'):
- p = os.environ.get(var)
- if p:
- cands.append(Path(p) / 'Internet Explorer' / 'iexplore.exe')
- cands += [
- Path(r'C:\\Program Files\\Internet Explorer\\iexplore.exe'),
- Path(r'C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe'),
- ]
- for c in cands:
- if c.is_file():
- return c
- return None
复制代码
IE命令行参数是精华:-k全屏kiosk无地址栏工具栏,F11退出;-private无痕;-nomerge强制独立进程,避免复用登录态;-extoff禁用加载项,排查插件冲突白屏常用;-nohangrecovery禁用挂起恢复;-noframemerging禁止帧合并。老系统常卡在半死IE进程,先杀再开能减少白屏工单。
- import subprocess
- def kill_ie(force=True):
- cmd = ['taskkill']
- if force:
- cmd.append('/F')
- cmd += ['/IM', 'iexplore.exe']
- r = subprocess.run(cmd, capture_output=True, text=True,
- encoding='gbk', errors='ignore')
- return r.returncode == 0
复制代码
注意taskkill输出编码是GBK,subprocess.run要指定encoding='gbk'和errors='ignore',否则中文Windows可能UnicodeDecodeError。returncode==0表示确实杀到,128表示本来没有进程。
脱离父进程也很关键。Popen默认浏览器是EXE子进程,父进程退出可能带走子进程或残留控制台。Windows加DETACHED_PROCESS和CREATE_NEW_PROCESS_GROUP。
- def detach_flags():
- if os.name != 'nt':
- return 0
- return (getattr(subprocess, 'DETACHED_PROCESS', 0)
- | getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0))
- def launch_ie(ie, url, kiosk=False, private=False, nomerge=False, extoff=False):
- args = [str(ie)]
- if kiosk:
- args.append('-k')
- if private:
- args.append('-private')
- if nomerge:
- args.append('-nomerge')
- if extoff:
- args.append('-extoff')
- args.append(url)
- proc = subprocess.Popen(args, creationflags=detach_flags(), close_fds=True)
- return proc.pid
复制代码
配置化:地址不要写死,config.ini与EXE同目录,运维改地址无需重打包。
- [target]
- url = http://10.0.0.1/oa
- [browser]
- engine = auto
- kiosk = false
- private = false
- nomerge = false
- extoff = false
- user_data_dir =
复制代码
读取时用encoding='utf-8-sig',避免记事本另存带BOM导致[target]第一行解析失败。布尔值别用bool()强转,bool('false')为True,应按1/true/yes/on白名单判断。engine可选auto/ie/edge;auto下优先IE,没有IE再找Edge;Edge IE模式调用msedge.exe --ie-mode-force url,kiosk加--kiosk,独立profile用--user-data-dir。
打包:pyinstaller -F -w -i app.ico --name IELauncher ie_launcher.py。日志设计:打包后日志目录取sys.executable所在目录,开发态取脚本目录;无写权限时退回tempfile.gettempdir()。用-w时看不到控制台,排查加--debug或看文件日志。CLI示例:python ie_launcher.py --info;python ie_launcher.py http://10.0.0.1/oa -k;python ie_launcher.py --kill -p。
避坑清单:1 Win10 22H2/Win11上iexplore.exe可能跳转Edge,需考虑Edge IE模式并确认目标系统策略。2 -w打包后报错看不见,用--debug和文件日志。3 EXE放C:\\Program Files下无写权限,日志退回临时目录。4 32位Python打包访问System32被静默重定向,注意架构与32位ActiveX兼容。5 杀毒软件误报,需签名或白名单策略。6 ActiveX插件是32位的,优先32位IE或32位打包。7 中文路径与编码,配置用utf-8-sig,taskkill用gbk。8 PowerShell或计划任务调用时注意路径,使用绝对路径并设置工作目录。排查流程建议先--info看IE/Edge路径和版本,再--debug看启动参数和异常,再用-extoff排除加载项冲突,最后用--kill清理残留进程。
总结:核心不是打开浏览器,而是可靠定位iexplore.exe、正确传IE参数、让子进程脱离父进程、配置外置、打包后保留可观测日志。按这个结构实现,内网IE小工具才能稳定交付。 |