JavaEar 专注于收集分享传播有价值的技术资料

process.terminate()不能用于铬/火狐子的工作,如果一个浏览器窗口已经存在 (process.terminate() doesn't work for a chrome / firefox subprocess if a browser window is already present)

I am launching a sub-process using the following command:

p=subprocess.Popen(["google-chrome","--new-window","http://www.hckrnews.com"])

I need to kill this process after sometime, so I'm using:

time.sleep(t)
p.terminate()

This works only if no instance of the browser is already open. If a browser window is already present, a new window opens but does not terminate after specified time.

I also tried the method given in this question, but that also doesn't work in case of already present window.

2个回答

    最佳答案
  1. This is not a python problem, and your code doesn't contain errors. It's a problem with the browsers. When you launch the firefox or chrome's executable with --new-window a new window is opened in the existing instance of the browser.

    In other words the process you just started connects to the already existing process of firefox/chrome and instructs that process to open a new window and then terminates. So when you call terminate() nothing really happens because the process you started already ended.

    You can check this with few lines of code:

    >>> 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
    

    You should tell the browser to open a new instance instead of a new window. Firefox has a -new-instance option, even though, when trying to use it, the only thing I get is that a pop-up appears saying that I cannot open two instances of the browser. Whether opening multiple instances of a browser in a certain OS session is allowed depends on the browser and may not be possible.

    On Chrome I believe you can open a new session telling Chrome to use a different directory to store its data (see here for example). No idea whether this is possible in firefox.

  2. 参考答案2
  3. As explained in Bakuriu's answer, --new-window creates a new window, but under an existing instance of firefox, if there is one. If there is no existing instance, a new one is created.

    It is possible to use -new-instance to tell Firefox to start a new instance for a different firefox user profile. The profile must already exist and this is limited to one instance per profile. A new profile can be created interactively with firefox -P -new-instance, and a new instance can then be started with firefox -P <profile_name> -new-instance. Mozilla's profile documentation is here.

    It should be possible to programmatically create the profile - after all it is just a directory and an entry in the ~/.mozilla/profiles.ini file. Of course, this is for Firefox only, chrome might be completely different (or impossible?). An example:

    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)