¿Cómo matar al servidor X sin cabeza iniciado a través de Python?

Quiero obtener capturas de pantalla de una página web en Python. Para esto estoy usando 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) 

Básicamente llama a xvfb-run con los argumentos correctos. Pero el man xvfb dice:

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.

Así que eso significa que esta secuencia de comandos será si todo esto está en un bucle, (para obtener varias capturas de pantalla) a menos que el servidor X esté muerto. ¿Cómo puedo hacer eso?

La documentación para os.execvp establece:

Todas estas funciones ejecutan un nuevo progtwig, reemplazando el proceso actual; No vuelven. [..]

Entonces, después de llamar a os.execvp no se os.execvp ninguna otra statement en el progtwig. Es posible que desee utilizar subprocess.Popen lugar:

El módulo de subprocess permite generar nuevos procesos, conectarse a sus canales de entrada / salida / error y obtener sus códigos de retorno. Este módulo pretende reemplazar varios módulos y funciones más antiguos, como:

Usando subprocess.Popen , el código para ejecutar xlogo en el servidor virtual de framebuffer X se convierte en:

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

Ahora el problema es que xvfb-run lanza Xvfb en un proceso en segundo plano. Al llamar a process.kill() no se eliminará Xvfb (al menos no en mi máquina …). He estado jugueteando con esto un poco, y hasta ahora lo único que funciona para mí es:

 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) 

Entonces, este código lee el ID de proceso de Xvfb desde /tmp/.X99-lock y envía una interrupción al proceso. Funciona, pero produce un mensaje de error de vez en cuando (aunque supongo que puede ignorarlo). Esperemos que alguien más pueda proporcionar una solución más elegante. Aclamaciones.