web-dev-qa-db-fra.com

Comment arrêter correctement l'exécution de phantomjs

J'ai initié et fermé phantomjs dans Python avec ce qui suit

from Selenium import webdriver    
driver = webdriver.PhantomJS()
driver.get(url)
html_doc = driver.page_source
driver.close()

pourtant, une fois l'exécution du script terminée, je trouve toujours une instance de phantomjs dans mon moniteur d'activité Mac. Et chaque fois que j'exécute le script, un nouveau processus phantomjs est créé.

Comment dois-je fermer le pilote?

38
CptNemo

La méthode .close() n'est pas garantie de libérer toutes les ressources associées à une instance de pilote. Notez que ces ressources incluent, mais ne sont pas limitées à, l'exécutable du pilote (PhantomJS, dans ce cas). La méthode .quit() est conçue pour libérer toutes les ressources d'un pilote, y compris la fermeture du processus exécutable.

18
JimEvans

En juillet 2016, driver.close() et driver.quit() ne me suffisaient pas. Cela a tué le processus node mais pas le processus enfant phantomjs qu'il a généré.

Après la discussion sur ce problème GitHub , la seule solution qui a fonctionné pour moi était d'exécuter:

import signal

driver.service.process.send_signal(signal.SIGTERM) # kill the specific phantomjs child proc
driver.quit()                                      # quit the node proc
45
leekaiinthesky

Veuillez noter que cela causera évidemment des problèmes si vous avez plusieurs threads/processus démarrant PhantomJS sur votre machine.

J'ai vu plusieurs personnes se débattre avec le même problème, mais pour moi, la solution de contournement/hack la plus simple était d'exécuter ce qui suit à partir de la ligne de commande via Python APRÈS avoir invoqué driver.close() ou driver.quit():

pgrep phantomjs | xargs kill
21
whirlwin

J'avais un problème similaire sur une machine Windows. Je n'ai pas eu de chance non plus

driver.close()

ou

driver.quit()

fermeture de la fenêtre PhantomJS, mais quand j'ai utilisé les deux, la fenêtre PhantomJS s'est finalement fermée et s'est fermée correctement.

driver.close()
driver.quit()
6
John H.

driver.quit() ne fonctionnait pas pour moi sur Windows 10, j'ai donc fini par ajouter la ligne suivante juste après avoir appelé driver.close():

os.system('taskkill /f /im phantomjs.exe')

/f = force
/im = by image name

Et puisqu'il s'agit d'une solution Windows uniquement, il peut être judicieux de ne l'exécuter que si os.name == 'nt'

2
FoxMulder900

Quel est le système d'exploitation que vous utilisez? Je pense que cela correspond au cas du suivant, si vous utilisez le système d'exploitation POSIX.

Je crée une pull request, mais elle a été rejetée. https://github.com/SeleniumHQ/Selenium/pull/2244

Mais je pense évidemment que le corriger. Par conséquent, j'ai émis un problème. https://github.com/SeleniumHQ/Selenium/issues/2272

La cause première de ce problème est que la méthode de fin des phatmojs en mode pilote fantôme est incorrecte. Il ne s'agit pas d'utiliser l'API d'arrêt des fantômes en mode pilote fantôme à la fin.

Dans le cas de phantomjs que vous avez installés dans npm sur Linux ou OSX, A Selenium appelle Popen pour phantomjs, A phantomjs appelle spawn pour lib/phantomjs.js. A cette époque, un sélénium est parent, un phantomjs est enfant et lib/phantomjs.js est petit-enfant.

Vous appelez quit () dans le parent (Selenium), il envoie SIGTERM à l'enfant (phantomjs). et un enfant (phantomjs) envoie SIGTERM à son petit-enfant (lib/phantomjs.js) dans la fonction de gestionnaire SIGTERM de l'enfant.

Un petit-enfant sera un zombie lorsque le parent enverra SIGKILL à l'enfant avant que l'enfant n'envoie SIGTERM à son petit-enfant.

Cette requête d'extraction ttps: //github.com/SeleniumHQ/Selenium/pull/2244 doit être arrêtée en utilisant l'api d'arrêt du mode pilote fantôme.

 def send_remote_shutdown_command(self):
      super(Service, self).send_remote_shutdown_command()  ## ADD A NEW LINE HERE
      if self._cookie_temp_file:
          os.close(self._cookie_temp_file_handle)
          os.remove(self._cookie_temp_file)

Autres solutions, dormir entre "self.process.ternimate ()" et "self.process.kill ()". ttps: //github.com/SeleniumHQ/Selenium/blob/051c8b110a1aec35247cd45fa4db85c6e522cdcb/py/Selenium/webdriver/common/service.py#L151-L153

        self.process.terminate()
        time.sleep(1)  ## ADD A NEW LINE HERE
        self.process.kill()
        self.process.wait()
2
TakesxiSximada

J'ai également un script python exécuté sur mon mac en utilisant Selenium pour faire des choses en utilisant PhantomJS comme pilote Web.

Lorsque mon test est en cours, il y a trois processus à noter:

$ ps -ef | grep [p]hantomjs
  501 28085 24925   0  9:03pm ttys002    0:00.34 python test.py
  501 28088 28085   0  9:03pm ttys002    0:00.14 node /usr/local/bin/phantomjs --cookies-file=/var/folders/nq/hjz03w6d4fs620197d_zwg0m0000gn/T/tmp8xLNaH --webdriver=55075
  501 28090 28088   0  9:03pm ttys002    0:00.71 /usr/local/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs --cookies-file=/var/folders/nq/hjz03w6d4fs620197d_zwg0m0000gn/T/tmp8xLNaH --webdriver=55075

Notez la deuxième colonne qui sont les numéros de processus, et la troisième qui sont les processus parent. Mon script de test est le parent. Il y a un processus de nœud qui a mon script de test en tant que parent, puis il y a un autre processus PhantomJS dont le parent est le processus de nœud. Ne me demandez pas pourquoi il y a deux processus PhantomJS, je suppose que c'est juste comment il est conçu pour fonctionner?

Quoi qu'il en soit, dans le moniteur d'activité de mon Mac, je peux voir ceci:

enter image description here

Notez le numéro PID 28090.

Une fois mon test terminé, les processus traînent, tout comme vous aussi. Si je vérifie les processus en cours d'exécution, je peux voir:

$ ps -ef | grep [p]hantomjs
  501 28090     1   0  9:03pm ttys002    0:18.93 /usr/local/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs --cookies-file=/var/folders/nq/hjz03w6d4fs620197d_zwg0m0000gn/T/tmp8xLNaH --webdriver=55075

Il me semble donc que driver.quit() quitte le processus de nœud, celui avec le numéro PID 28088, mais il laisse son enfant orphelin. Je ne sais pas si c'est intentionnel. Si ce n'est pas intentionnel, je pense qu'il n'y a pas de moyen "approprié" de quitter ce processus dans votre code.

Par conséquent, j'utiliserais l'équivalent de votre langue de kill -9 28090, Juste après driver.quit()

0
Sebastian