Как убить безголовый X-сервер, запущенный через Python?

Я хочу получить скриншоты веб-страницы на Python. Для этого я использую http://github.com/AdamN/python-webkit2png/ .

    newArgs = ["xvfb-run", "--server-args=-screen 0, 640x480x24", sys.argv[0]]
    for i in range(1, len(sys.argv)):
        if sys.argv[i] not in ["-x", "--xvfb"]:
            newArgs.append(sys.argv[i])
    logging.debug("Executing %s" % " ".join(newArgs))
    os.execvp(newArgs[0], newArgs)

В основном вызывает xvfb-run с правильными аргументами. Но man xvfb говорит:

Note that the demo X clients used in the above examples will not exit on their own, so they will have to be killed before xvfb-run will exit.

Это означает, что этот скрипт будет ‹????›, если все это зациклится (чтобы получить несколько снимков экрана), если только X-сервер не будет убит. Как я могу это сделать?


person agiliq    schedule 17.11.2009    source источник
comment
webkit2png.py должен закрыться после создания снимка экрана, его не нужно убивать.   -  person Denis Otkidach    schedule 17.11.2009
comment
Да, но если я зацикливаюсь внутри webkit2png.py, он сам не умрет.   -  person agiliq    schedule 17.11.2009
comment
В чем причина использования бесконечного (while True) цикла вместо нескольких итераций (for i in range(n)) или break по прошествии некоторого времени?   -  person Denis Otkidach    schedule 17.11.2009


Ответы (1)


В документации для os.execvp указано:

Все эти функции выполняют новую программу, заменяя текущий процесс; они не возвращаются. [..]

Таким образом, после вызова os.execvp никакие другие операторы в программе выполняться не будут. Вместо этого вы можете использовать subprocess.Popen:

Модуль subprocess позволяет создавать новые процессы, подключаться к их каналам ввода/вывода/ошибок и получать их коды возврата. Этот модуль предназначен для замены нескольких других, более старых модулей и функций, таких как:

Используя subprocess.Popen, код для запуска xlogo на X-сервере виртуального фреймбуфера становится таким:

import subprocess
xvfb_args = ['xvfb-run', '--server-args=-screen 0, 640x480x24', 'xlogo']
process = subprocess.Popen(xvfb_args)

Теперь проблема в том, что xvfb-run запускает Xvfb в фоновом режиме. Вызов process.kill() не убьет Xvfb (по крайней мере, не на моей машине...). Я немного возился с этим, и пока единственное, что работает для меня, это:

import os
import signal
import subprocess

SERVER_NUM = 99  # 99 is the default used by xvfb-run; you can leave this out.

xvfb_args = ['xvfb-run', '--server-num=%d' % SERVER_NUM,
             '--server-args=-screen 0, 640x480x24', 'xlogo']
subprocess.Popen(xvfb_args)

# ... do whatever you want to do here...

pid = int(open('/tmp/.X%s-lock' % SERVER_NUM).read().strip())
os.kill(pid, signal.SIGINT)

Таким образом, этот код считывает идентификатор процесса Xvfb из /tmp/.X99-lock и отправляет процессу прерывание. Это работает, но время от времени выдает сообщение об ошибке (хотя я полагаю, вы можете его игнорировать). Надеюсь, кто-то другой может предоставить более элегантное решение. Ваше здоровье.

person Stephan202    schedule 18.11.2009