Je voudrais tester plusieurs agents d'utilisateurs mobiles avec du sélénium et du chrome. J'utilise python 3.6 et je déploie sur heroku. Basé sur http://chromedriver.chromium.org/mobile-emulation .
Vous pouvez télécharger mon projet pour Windows et Heroku sur:
https://github.com/kc1/mobiletest
(gardez à l'esprit que si vous déployez sur heroku, vous devez définir FLASK_CONFIG en production. Veuillez également noter que le code du projet est légèrement différent de celui de cette question car j'ai joué avec le code au cours de la semaine dernière.)
J'ai:
def some_long_calculation():
driver = create_chromedriver('kkk')
# driver = create_chromedriver()
driver.get("https://www.yahoo.com/")
.....
et :
def create_chromedriver(ua=False):
options = webdriver.ChromeOptions()
CHROMEDRIVER_PATH = os.getenv('$HOME') or basedir+'/chromedriver.exe'
FLASK_CONFIG = os.getenv('FLASK_CONFIG')
if ua:
mobile_emulation = {"deviceName": "Nexus 5"}
options.add_experimental_option("mobileEmulation", mobile_emulation)
if FLASK_CONFIG and FLASK_CONFIG == "production":
CHROMEDRIVER_PATH = '/app/.chromedriver/bin/chromedriver'
GOOGLE_CHROME_SHIM = os.getenv('$GOOGLE_CHROME_SHIM') or 'no path found'
options.binary_location = '/app/.apt/usr/bin/google-chrome-stable'
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
return webdriver.Chrome(executable_path=CHROMEDRIVER_PATH, options=options)
Si je l'exécute localement avec le navigateur mobile activé, cela fonctionne comme prévu:
Si je l'exécute sur heroku avec le navigateur mobile activé:
Ensuite, je l'ai essayé sur heroku avec l'utilisateur mobile désactivé, je reçois:
Donc, au moins, je sais que la configuration fonctionne jusqu'à chrome et chromedriver.
journaux heroku:
2018-07-15T17:37:53.967643+00:00 app[web.1]: driver = create_chromedriver('kkk')
2018-07-15T17:37:53.967637+00:00 app[web.1]: png = some_long_calculation()
2018-07-15T17:37:53.967645+00:00 app[web.1]: File "/app/app/main/cl.py", line 120, in create_chromedriver
2018-07-15T17:37:53.967640+00:00 app[web.1]: File "/app/app/main/cl.py", line 123, in some_long_calculation
2018-07-15T17:37:53.967648+00:00 app[web.1]: return webdriver.Chrome(executable_path=CHROMEDRIVER_PATH, options=options)
2018-07-15T17:37:53.967651+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/chrome/webdriver.py", line 75, in __init__
2018-07-15T17:37:53.967654+00:00 app[web.1]: desired_capabilities=desired_capabilities)
2018-07-15T17:37:53.967656+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/remote/webdriver.py", line 156, in __init__
2018-07-15T17:37:53.967659+00:00 app[web.1]: self.start_session(capabilities, browser_profile)
2018-07-15T17:37:53.967661+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/remote/webdriver.py", line 251, in start_session
2018-07-15T17:37:53.967669+00:00 app[web.1]: response = self.command_executor.execute(driver_command, params)
2018-07-15T17:37:53.967664+00:00 app[web.1]: response = self.execute(Command.NEW_SESSION, parameters)
2018-07-15T17:37:53.967667+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/remote/webdriver.py", line 318, in execute
2018-07-15T17:37:53.967672+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/remote/remote_connection.py", line 472, in execute
2018-07-15T17:37:53.967674+00:00 app[web.1]: return self._request(command_info[0], url, body=data)
2018-07-15T17:37:53.967677+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/Selenium/webdriver/remote/remote_connection.py", line 496, in _request
2018-07-15T17:37:53.967679+00:00 app[web.1]: resp = self._conn.getresponse()
2018-07-15T17:37:53.967682+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/http/client.py", line 1331, in getresponse
2018-07-15T17:37:53.967685+00:00 app[web.1]: response.begin()
2018-07-15T17:37:53.967687+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/http/client.py", line 297, in begin
2018-07-15T17:37:53.967695+00:00 app[web.1]: line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
2018-07-15T17:37:53.967690+00:00 app[web.1]: version, status, reason = self._read_status()
2018-07-15T17:37:53.967698+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/socket.py", line 586, in readinto
2018-07-15T17:37:53.967692+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/http/client.py", line 258, in _read_status
2018-07-15T17:37:53.967700+00:00 app[web.1]: return self._sock.recv_into(b)
2018-07-15T17:37:53.967712+00:00 app[web.1]: ConnectionResetError: [Errno 104] Connection reset by peer
Comment puis-je réparer cela?
ÉDITER:
Merci pour votre réponse détaillée. J'ai changé le code pour incorporer les drapeaux que vous avez mentionnés. Chrome est 67.0.3396.99. Chromedriver est 2.40 et Selenium est 3.13. Malheureusement, il n'y a aucun changement dans le résultat. Je reçois toujours la même erreur. En ce qui concerne votre étape 2 et 3. Je déploie actuellement sur heroku donc je n'ai pas le contrôle total des variables d'environnement. Y a-t-il un moyen de faire ces changements en utilisant python?
EDIT 2:
Comme j'y pense plus sur https://sites.google.com/a/chromium.org/chromedriver/mobile-emulation l'exemple utilise
from Selenium import webdriver
mobile_emulation = { "deviceName": "Nexus 5" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Remote(command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities = chrome_options.to_capabilities())
Suggérez-vous que le navigateur est à ' http://127.0.0.1:4444/wd/hub '
En général, lorsqu'un client se termine brutalement sans fermer la connexion, un RST packet
Est envoyé par la pile TCP/IP du système d'exploitation sous-jacent. Python convertit cela en une exception avec le texte Réinitialisation de la connexion par l'homologue . Selon votre pile d'erreur trace cela signifie qu'une fois que self._read_status()
a été invoquée (en interne) Python supposé recevoir quelque chose mais la connexion a été soudainement interrompue et Python vous informe de cette erreur en levant l'exception:
ConnectionResetError: [Errno 104] Connection reset by peer
La situation est quelque peu similaire à cette expression :
"Réinitialisation de la connexion par l'homologue" est l'équivalent TCP/IP du claquement du téléphone sur le crochet. C'est plus poli que simplement de ne pas répondre, laissant une pendaison. Mais ce n'est pas le FIN-ACK attendu du converseur TCP/IP vraiment poli.
Il peut y avoir plusieurs probabilités derrière cette erreur comme suit.
Une solution rapide et précise consistera à ajouter quelques-uns ChromeOptions recommandés ainsi que celui existant comme suit:
options.add_argument("start-maximized"); // open Browser in maximized mode
options.add_argument("disable-infobars"); // disabling infobars
options.add_argument("--disable-extensions"); // disabling extensions
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage"); // overcome limited resource problems
puis
return webdriver.Chrome(executable_path=CHROMEDRIVER_PATH, options=options)
Remarque : Vous devez supprimer l'argument options.add_argument('--disable-gpu')
car il s'applique uniquement au système d'exploitation Windows.
Quelques points:
Python Chrome Mobile Emulation
la Clé et Value la paire semble être "deviceName": "Google Nexus 5"
(pas "deviceName": "Nexus 5"
)Vous pouvez modifier votre code pour invoquer Remote()
de l'une des manières suivantes:
Appel de Remote()
à DesiredCapabilities()
:
from Selenium import webdriver
# import DesiredCapabilities was missing in your program
from Selenium.webdriver.common.desired_capabilities import DesiredCapabilities
mobile_emulation = { "deviceName": "Google Nexus 5" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
capabilities = DesiredCapabilities.CHROME
capabilities = options.to_capabilities()
driver = webdriver.Remote(command_executor='http://127.0.0.1:4444/wd/hub', desired_capabilities = capabilities)
Vous trouverez une discussion similaire sur l'invocation de Remote()
à ChromeOptions()
dans Comment ajouter des options de sélénium chrome à 'desireCapabilities'?
Appel de Remote()
à ChromeOptions()
:
from Selenium import webdriver
mobile_emulation = { "deviceName": "Google Nexus 5" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Remote(command_executor='http://127.0.0.1:4444/wd/hub', options=chrome_options)
Vous trouverez une discussion similaire sur l'appel de Remote()
à ChromeOptions()
dans Remote WebDriver UnreachableBrowserException: impossible de démarrer une nouvelle session
Webdriver.Android
Getting started with Selendroid
Si l'erreur persiste, effectuez les tâches de mise à niveau/nettoyage suivantes:
driver.quit()
dans la méthode tearDown(){}
pour fermer et détruire les instances WebDriver et Web Client avec élégance.@Test
.À la recherche d'une solution granulaire à une erreur spécifique, je suis entré dans Amazon S3 et "Connection Reset by Peer" où Garry Dolley estivale la cause du problème est une combinaison des facteurs mentionnés ci-dessous:
Les noyaux Linux 2.6.17+ ont augmenté la taille maximale de la fenêtre/du tampon TCP, et cela a commencé à entraîner la perte d'autres équipements, s'il ne pouvait pas gérer suffisamment grand TCP windows. L'engrenage réinitialisera la connexion, et nous voyons cela comme un message "Connection reset by peer".
Une solution potentielle sera de mettre les entrées suivantes dans /etc/sysctl.conf
:
Remarque : ce correctif est simple, mais il ralentira votre échange de débit maximal de téléchargements plus rapides.
Le cas échéant, assurez-vous que/etc/hosts sur votre système contient l'entrée suivante:
127.0.0.1 localhost.localdomain localhost
Voici quelques-unes des discussions connexes:
Voici les références de cette discussion:
Le message d'erreur spécifique indique
Android L'adresse IP du serveur est introuvable.
Pour moi, cela indique que le navigateur essaie de rechercher une entrée DNS pour Android
, qui n'est pas un TLD valide. Par hasard, le navigateur tente-t-il d'accéder à http://Android
, plutôt que quelque chose comme https://www.google.com
? Je peux reproduire ce même message d'erreur dans mon propre Chrome en tapant http://Android
dans la barre d'adresse. Cela m'amène à croire que la spécification d'une URL appropriée pour le navigateur devrait résoudre le problème.