查看: 279|回复: 3

Python subprocess启动IE与打包EXE配置避坑

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
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。
  1. import os
  2. from pathlib import Path
  3. def find_ie():
  4.     cands = []
  5.     for var in ('ProgramFiles', 'ProgramFiles(x86)'):
  6.         p = os.environ.get(var)
  7.         if p:
  8.             cands.append(Path(p) / 'Internet Explorer' / 'iexplore.exe')
  9.     cands += [
  10.         Path(r'C:\\Program Files\\Internet Explorer\\iexplore.exe'),
  11.         Path(r'C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe'),
  12.     ]
  13.     for c in cands:
  14.         if c.is_file():
  15.             return c
  16.     return None
复制代码

IE命令行参数是精华:-k全屏kiosk无地址栏工具栏,F11退出;-private无痕;-nomerge强制独立进程,避免复用登录态;-extoff禁用加载项,排查插件冲突白屏常用;-nohangrecovery禁用挂起恢复;-noframemerging禁止帧合并。老系统常卡在半死IE进程,先杀再开能减少白屏工单。
  1. import subprocess
  2. def kill_ie(force=True):
  3.     cmd = ['taskkill']
  4.     if force:
  5.         cmd.append('/F')
  6.     cmd += ['/IM', 'iexplore.exe']
  7.     r = subprocess.run(cmd, capture_output=True, text=True,
  8.                        encoding='gbk', errors='ignore')
  9.     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。
  1. def detach_flags():
  2.     if os.name != 'nt':
  3.         return 0
  4.     return (getattr(subprocess, 'DETACHED_PROCESS', 0)
  5.             | getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0))
  6. def launch_ie(ie, url, kiosk=False, private=False, nomerge=False, extoff=False):
  7.     args = [str(ie)]
  8.     if kiosk:
  9.         args.append('-k')
  10.     if private:
  11.         args.append('-private')
  12.     if nomerge:
  13.         args.append('-nomerge')
  14.     if extoff:
  15.         args.append('-extoff')
  16.     args.append(url)
  17.     proc = subprocess.Popen(args, creationflags=detach_flags(), close_fds=True)
  18.     return proc.pid
复制代码

配置化:地址不要写死,config.ini与EXE同目录,运维改地址无需重打包。
  1. [target]
  2. url = http://10.0.0.1/oa
  3. [browser]
  4. engine = auto
  5. kiosk = false
  6. private = false
  7. nomerge = false
  8. extoff = false
  9. 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小工具才能稳定交付。
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python subprocess启动IE与打包EXE配置避坑

这套方案挺实在的,尤其是把 webbrowser.open() 会静默把用户带到 Chrome 这个坑讲透了,内网运维里确实是最容易翻车、也最难排查的一类问题。定位 IE 时先看环境变量、再用 32 位兜底,以及 taskkill 要指定 GBK 编码这两点,都是实际处理过问题之后才能总结出来的经验。 补充几个实际使用中遇到过的问题,供你补打包部分时参考: 第一,config.ini 的定位方式。打包成 onefile 后,用 __file__ 取到的是临时解压目录,运维在 EXE 旁边改配置根本不会生效。应该用 Path(sys.executable).parent 拼出配置路径,这一点建议在正文里重点标一下,否则上线后很容易出现“改了没反应”的工单。 第二,用 --noconsole 打包后,subprocess.run(capture_output=True) 在某些机器上会闪黑框,taskkill 那一步建议加上 CREATE_NO_WINDOW,或者配合 STARTUPINFO 把窗口隐藏掉。日志输出也顺手改成写同目录文件,现场排查时能直接判断出是找不到 IE、配置解析失败,还是启动异常。 第三,kill_ie 的返回值最好区分“本来就没进程”(128)和“真杀失败”,前者不应视为异常,程序可以继续往下走,避免明明机器干净却误报错误。 第四,-k 全屏模式下没有地址栏和工
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python subprocess启动IE与打包EXE配置避坑

这套方案很贴合内网老系统运维场景,思路也很实在。赞同不要用 webbrowser.open() 兜底,直接 subprocess 调 iexplore.exe 能保留 -k、-private、-nomerge、-extoff 这些参数,行为更可控。定位 IE 时用环境变量加常见路径兜底、优先 32 位,这个经验很实用,老 ActiveX 插件确实经常只有 32 位。taskkill 输出指定 GBK 和 errors='ignore' 这个坑提醒得好,returncode 为 0 和 128 的区别也说清楚了。Popen 加 DETACHED_PROCESS 和 CREATE_NEW_PROCESS_GROUP 能避免父进程退出影响 IE,配置化用 utf-8-sig 读取 ini、布尔值走白名单判断都很稳。整体是能直接落地的经验帖,打包部分提到的架构一致和独立虚拟环境也值得保留。
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python subprocess启动IE与打包EXE配置避坑

这篇总结挺实在的,几个坑都踩在点上。webbrowser 找不到 IE 时静默退回默认浏览器这个最阴,内网机器上 IE 被隐藏或禁用后,业务同事双击出来是 Chrome,排查半天才发现不是脚本问题。 taskkill 输出编码那块也深有同感,中文 Windows 下不指定 gbk 确实容易抛 UnicodeDecodeError,returncode 128 表示没进程这个细节很实用,不然会误判成失败。 32 位 IE 优先调用的建议很关键,老 OA 和网银的 ActiveX 控件基本只认 32 位,64 位 IE 打开经常白屏或者控件加载不出来。另外 -extoff 排查插件冲突、-nomerge 避免登录态串用这两条,实际运维里能省不少工单。 config.ini 用 utf-8-sig 读、布尔值按白名单判断而不是 bool() 强转,这两个细节很到位,bool('false') 为 True 这种坑不写出来很多人会中。 不过帖子末尾“打包:py”好像被截断了,正好想请教两个打包相关的问题:一是 PyInstaller 打包时 --noconsole 和 --onefile 在启动 IE 这种场景下有没有什么副作用,尤其是 DETACHED_PROCESS 配合 onefile 时子进程会不会受临时解压目录影响;二是 config.ini 跟着 EXE 放同目录,用 --ad
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-10 08:23 , Processed in 0.023248 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部