Использование python, selenium и phantomjs в openshift (разрешение на привязку сокета отказано?)

Хорошо, я нахожусь в конце своей привязи, пытаясь заставить phantomJS работать с селеном в среде openshift. Я скачал бинарный файл phantomjs с помощью ssh и даже могу запустить его в оболочке. Но когда дело доходит до запуска службы webdriver, использующей селен, я продолжаю получать эту ошибку трассировки, независимо от того, какие аргументы я ввел.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/var/lib/openshift/576e22027628e1fb13000211/python/virtenv/venv/lib/python3.3/site-packages/selenium/webdriver/phantomjs/webdriver.py", line 50, in __init__
    service_args=service_args, log_path=service_log_path)
  File "/var/lib/openshift/576e22027628e1fb13000211/python/virtenv/venv/lib/python3.3/site-packages/selenium/webdriver/phantomjs/service.py", line 50, in __init__
    service.Service.__init__(self, executable_path, port=port, log_file=open(log_path, 'w'))
  File "/var/lib/openshift/576e22027628e1fb13000211/python/virtenv/venv/lib/python3.3/site-packages/selenium/webdriver/common/service.py", line 33, in __init__
    self.port = utils.free_port()
  File "/var/lib/openshift/576e22027628e1fb13000211/python/virtenv/venv/lib/python3.3/site-packages/selenium/webdriver/common/utils.py", line 36, in free_port
    free_socket.bind(('0.0.0.0', 0))

PermissionError: [Errno 13] Permission denied

Не уверен, что происходит, я должен привязать к IP-адресу? Если так, то я пытался использовать служебные аргументы, но это не помогло.

1 ответ

Я столкнулся с теми же проблемами, пытаясь запустить phantomJS в моем приложении Openshift Django, работающем на Python 3. Наконец мне удалось заставить его работать, вот как:

Основная проблема, которую необходимо преодолеть, заключается в том, что Openshift не позволяет приложениям связываться на локальном хосте (ни "0.0.0.0", ни "127.0.0.1"). Таким образом, смысл заключается в том, чтобы вместо этого привязать фактический IP-адрес вашего Openshift Gear

Вы должны решить эту проблему на уровне ghostdriver, а также в привязке Python-selenium.

Призрачный Драйвер (PhantomJS двоичный)

К сожалению, как блестяще объяснил Паоло Бернарди в этом посте: http://www.bernardi.cloud/2015/02/25/phantomjs-with-ghostdriver-on-openshift/ вы должны использовать для этого патчированную версию фантомов, поскольку выпущенная версия не позволяет связываться с указанным IP. Бинарный файл, связанный Paolo, не работал на моем картридже Python3, но этот работал отлично: https://github.com/jrestful/server/blob/master/seo/phantomjs-1.9.8-patched.tar.gz?raw=true (см. вопрос " Попытка запустить PhantomJS в OpenShift: невозможно исправить GhostDriver, чтобы он мог связываться с IP-адресом сервера")

Загрузите этот двоичный файл phantomjs в app-root / data / phantomjs / bin (например) и убедитесь, что он работает:

> chmod 711 app-root/data/phantomjs/bin/phantomjs

Теперь вы можете проверить, что можете привязать свой IP к этому бину (я выбрал номер порта 15002 для своего приложения, и я считаю, что вы можете выбрать любое значение, превышающее 15000):

> echo $OPENSHIFT_PYTHON_IP
127.13.XXX.XXX
> app-root/data/phantomjs/bin/phantomjs --webdriver=127.13.XXX.XXX:15002
PhantomJS is launching GhostDriver...
[INFO  - 2017-03-24T13:16:36.031Z] GhostDriver - Main - running on port 127.13.XXX.XXX:15002

Хорошо, теперь завершите этот процесс и перейдите к шагу 2: python webdriver

Пользовательский веб-драйвер Python-Selen для PhantomJS

Суть заключается в том, чтобы добавить IP-адрес для привязки в качестве параметра веб-драйвера PhantomJS.

Сначала я определил новые настройки для адаптации к ограничениям Openshift в своем файле settings.py

PHANTOMJS_BIN_PATH = os.path.join(os.getenv('OPENSHIFT_DATA_DIR'), 'phantomjs', 'bin', 'phantomjs')
PHANTOMJS_LOG_PATH = os.path.join(os.getenv('OPENSHIFT_LOG_DIR'), 'ghostdriver.log')

(убедитесь, что app-root / logs / доступен для записи, возможно, вам придется изменить его)

Затем мне пришлось переопределить класс PhantomJS Webdriver, чтобы указать IP-адрес в качестве аргумента. Вот моя собственная реализация:

from selenium.webdriver import phantomjs
from selenium.webdriver.common import utils
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

class MyPhantomJSService(phantomjs.service.Service):
    def __init__(self, executable_path, port=0, service_args=None, log_path=None, ip=None):
        if ip is None:
            self.ip = '0.0.0.0'
        else:
            self.ip = ip
        phantomjs.service.Service.__init__(self, executable_path, port, service_args, log_path)

    def command_line_args(self):
        return self.service_args + ["--webdriver=%s:%d" % (self.ip, self.port)]

    def is_connectable(self):
        return utils.is_connectable(self.port, host=self.ip)

    @property
    def service_url(self):
        """
        Gets the url of the GhostDriver Service
        """
        return "http://%s:%d/wd/hub" % (self.ip, self.port)


class MyPhantomWebDriver(RemoteWebDriver):
    """
    Wrapper to communicate with PhantomJS through Ghostdriver.

    You will need to follow all the directions here:
    https://github.com/detro/ghostdriver
    """

    def __init__(self, executable_path="phantomjs",
                 ip=None, port=0, desired_capabilities=DesiredCapabilities.PHANTOMJS,
                 service_args=None, service_log_path=None):
        """
        Creates a new instance of the PhantomJS / Ghostdriver.

        Starts the service and then creates new instance of the driver.

        :Args:
         - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
         - ip - IP sur lequel on veut se binder : c'est la spécificité de ce monkeypatch
         - port - port you would like the service to run, if left as 0, a free port will be found.
         - desired_capabilities: Dictionary object with non-browser specific
           capabilities only, such as "proxy" or "loggingPref".
         - service_args : A List of command line arguments to pass to PhantomJS
         - service_log_path: Path for phantomjs service to log to.
        """
        self.service = MyPhantomJSService(
            executable_path,
            port=port,
            service_args=service_args,
            log_path=service_log_path,
            ip=ip)
        self.service.start()

        try:
            RemoteWebDriver.__init__(
                self,
                command_executor=self.service.service_url,
                desired_capabilities=desired_capabilities)
        except Exception:
            self.quit()
            raise

        self._is_remote = False

    def quit(self):
        """
        Closes the browser and shuts down the PhantomJS executable
        that is started when starting the PhantomJS
        """
        try:
            RemoteWebDriver.quit(self)
        except Exception:
            # We don't care about the message because something probably has gone wrong
            pass
        finally:
            self.service.stop()

Наконец, вызовите этот пользовательский веб-драйвер вместо webdriver.PhantomJS(..., например:

from .myphantomjs import MyPhantomWebDriver

browser = MyPhantomWebDriver(executable_path=settings.PHANTOMJS_BIN_PATH, service_log_path=settings.PHANTOMJS_LOG_PATH, ip=os.getenv('OPENSHIFT_PYTHON_IP'), port=15002)

С этого момента вы можете использовать объект браузера как обычно

Другие вопросы по тегам