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

Я хочу получить скриншоты веб-страницы на 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-сервер не будет убит. Как я могу это сделать?

1 Ответ

4 голосов
/ 18 ноября 2009

Документация для 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 и отправляет процессу прерывание. Это работает, но время от времени выдает сообщение об ошибке (хотя, я думаю, вы можете его игнорировать). Надеюсь, кто-то еще сможет предложить более элегантное решение. Приветствия.

...