процесс.функция terminate() не работает для подпроцесса chrome / firefox, если окно браузера уже присутствует


Я запускаю подпроцесс, используя следующую команду:

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

Мне нужно убить этот процесс через некоторое время, поэтому я использую:

time.sleep(t)
p.terminate()

Это работает только в том случае, если ни один экземпляр браузера еще не открыт. Если окно браузера уже присутствует, новое окно открывается, но не завершается по истечении указанного времени.

Я также попробовал метод, приведенный в этом вопросе, но это также не работает в случае уже существующего окна.

2 4

2 ответа:

Это Не проблема python, и ваш код не содержит ошибок. Это проблема с браузерами. При запуске исполняемого файла firefox или chrome с помощью --new-window открывается новое окно в существующем экземпляре браузера.

Другими словами, процесс, который вы только что запустили, подключается к уже существующему процессу 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.

Как объяснено в ответе Бакуриу , --new-window создает новое окно, но под существующим экземпляром firefox, если таковой имеется. Если не существует существующего экземпляра, создается новый.

Можно использовать -new-instance, чтобы сказать Firefox, чтобы начать новый экземпляр для другой Профиль пользователя 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)