process.terminate() 对已存在浏览器窗口的 Chrome/Firefox 子进程无效
我正在使用以下命令启动一个子进程:
p=subprocess.Popen(["google-chrome","--new-window","http://www.hckrnews.com"])
我需要在一段时间后结束这个进程,所以我使用了:
time.sleep(t)
p.terminate()
这个方法只有在浏览器没有打开的情况下才有效。如果浏览器窗口已经打开,虽然会新开一个窗口,但在指定时间后并不会关闭。
我还尝试了这个问题中给出的方法,但在浏览器窗口已经存在的情况下,这个方法也不奏效。
2 个回答
正如Bakuriu的回答中所解释的,--new-window
这个命令可以在现有的Firefox窗口中打开一个新窗口。如果没有现有的窗口,它就会创建一个新的窗口。
你可以使用-new-instance
来告诉Firefox启动一个新的实例,用于不同的用户配置文件。这个配置文件必须已经存在,并且每个配置文件只能有一个实例。你可以通过命令firefox -P -new-instance
来交互式地创建一个新的配置文件,然后可以用firefox -P <profile_name> -new-instance
来启动这个新的实例。Mozilla的配置文件文档可以在这里找到。
理论上,你可以通过编程的方式创建这个配置文件——毕竟它只是一个目录和~/.mozilla/profiles.ini
文件中的一条记录。当然,这只适用于Firefox,Chrome可能完全不同(或者根本不行?)。下面是一个例子:
import tempfile
import subprocess
import shutil
import time
import ConfigParser
MOZILLA_PROFILES_INI = '.mozilla/firefox/profiles.ini'
PROFILE_SECTION = 'Profile1'
URL = 'http://www.hckrnews.com'
profile_dir = tempfile.mkdtemp()
# quick and dirty add new profile to profiles.ini, or update if already present.
config = ConfigParser.SafeConfigParser()
config.optionxform = str # preserve case of option names
config.read(MOZILLA_PROFILES_INI)
try:
config.add_section(PROFILE_SECTION)
except ConfigParser.DuplicateSectionError, exc:
pass
config.set(PROFILE_SECTION, 'Name', 'temp_profile')
config.set(PROFILE_SECTION, 'IsRelative', '0')
config.set(PROFILE_SECTION, 'Path', profile_dir)
# write out config with hack to remove added spaces around '=' - more care needed here as it just overwrites the global mozilla config!
class NoSpaceWriter(file):
def write(self, s):
super(NoSpaceWriter, self).write(s.replace(' = ', '='))
with NoSpaceWriter(MOZILLA_PROFILES_INI, 'w') as profiles_ini:
config.write(profiles_ini)
p = subprocess.Popen(['firefox', '-P', 'temp_profile', '-new-instance', URL])
time.sleep(10)
p.terminate()
shutil.rmtree(profile_dir, True)
这其实不是一个Python的问题,你的代码也没有错误。问题出在浏览器上。当你用 --new-window
启动Firefox或Chrome的可执行文件时,它会在已有的浏览器实例中打开一个新窗口。
换句话说,你刚启动的这个进程会连接到已经存在的Firefox或Chrome进程,然后指示那个进程打开一个新窗口,之后就结束了。所以当你调用 terminate()
时,实际上什么也不会发生,因为你启动的进程已经结束了。
你可以用几行代码来验证这一点:
>>> import subprocess
>>> p = subprocess.Popen(['firefox', '-new-window'])
>>> p.wait() # uh-oh. this should be blocking!
0
>>> p.terminate()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 1551, in terminate
self.send_signal(signal.SIGTERM)
File "/usr/lib/python2.7/subprocess.py", line 1546, in send_signal
os.kill(self.pid, sig)
OSError: [Errno 3] No such process
你应该告诉浏览器打开一个新的实例,而不是新窗口。Firefox有一个 -new-instance
的选项,不过当我尝试使用时,弹出的提示告诉我不能打开两个浏览器实例。是否允许在某个操作系统会话中打开多个浏览器实例,取决于浏览器本身,可能是不可行的。
在Chrome中,我相信你可以通过告诉Chrome使用不同的目录来存储数据,从而打开一个新会话(例如,查看 这里)。至于Firefox是否可以这样做,我就不太清楚了。