Как стать автором
Поиск
Написать публикацию
Обновить

Ускорение разработки с использованием Selenium

Уровень сложностиПростой

В статье описывается мой опыт работы с Selenium, включая основные трудности и ошибки, с которыми я столкнулся в процессе разработки. Я делюсь практичекими рекомендациями по ускорению разработки и повышению эффективности работы с этим инструментом.

Источник: https://www.selenium.dev/
Источник: https://www.selenium.dev/

Я начал использовать Selenium для парсинга сайтов. Начинал я с Requests + BeautifulSoup4, но их не всегда хватало. Одной из первых задач было спарсить более 1000 шаблонных сайтов клиентов (сайты располагались на нашем хостинге и обслуживались нами), для сбора данных с целью дальнейшей обработки.

Тогда я отлавливал каждый селектор в процессе запуска сессии Selenium и проверял правильно ли он находится (особенно доставляло удовольствие искать элементы в нескольких всплывающих окнах и iframe). Для этого при поиске каждого селектора я каждый раз перезапускал сессию webdriver, что занимало очень много времени. Еще тогда мне казалось что должен быть способ искать селекторы постепенно, не перезапуская сессию.

Решение с серверной обработкой на Django

В какой-то момент я поднял сервер на django, в котором была открыта сессия webdriver и были настроены функции для действий, в которые я POST-запросом передавал значения, которые обрабатывал django и передавал в функцию, которая работала с Selenium.

По мимо всей обработки в django функция выглядела примерно так:

def find_by_id(pk):
	driver.find_element_by_id(pk)

Синтаксис работы с Selenium отличался от современного, сейчас бы он выглядел:

def find_by_id(pk):
    driver.find_element(By.ID, pk)

Это позволяло не перезапускать сессию при каждом поиске селектора, но это все еще было нагромождением кода, которое хоть и ускоряло разработку, все еще оставалось медленным и проблемным.

Сейчас бы я написал подобное с использованием FastAPI, например так я писал кастомное API (адаптер) к ChatGTP, который через Selenium обращался к настоящему ChatGPT и возвращал его ответ.

Решение с использованием режима отладки Chrome

Хоть в обычных задачах я и предпочитаю Firefox, для Selenium Chrome оказался для меня удобнее. Всё что нам сейчас нужно - это открыть Chrome в режиме удаленной отладки и подключаться к нему с помощью webdriver.

Chrome с версией 115 и выше не требует отдельной установки драйвера для Selenium, поэтому установить нужно только Selenium:

pip install selenium

Запускаем Chrome в режиме удаленной отладки:

import os
import socket
import threading

class DebugChrome():
    def __init__(self, chrome_path: str = 'None'):
            if chrome_path == 'None':
                # Путь для Chrome по умолчанию
                # если используется другой - нужно передать путь к Chrome 
                # аргументом при вызове класса
                self.chrome_path = r'"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"'
            else:
                self.chrome_path = chrome_path

            # Вызываем функцию поиска свободного порта
            free_port = self._find_available_port()

            # Запускаем Chrome в режиме удаленной отладки
            self._launch_chrome_with_remote_debugging(free_port,
                                                      'https://www.google.com')

    def _find_available_port(self):
        # Находим свободный порт
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind(('', 0))
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            return s.getsockname()[1]

    def _launch_chrome_with_remote_debugging(self, port, url):
        # Запуск Chrome в режиме удаленной отладки

        def open_chrome():
            chrome_cmd = f"{self.chrome_path} --remote-debugging-port={port} --user-data-dir=remote-profile {url}"
            os.system(chrome_cmd)

        chrome_thread = threading.Thread(target=open_chrome)
        chrome_thread.start()
        print(f"port: {port}")

После запуска кода Chrome будет открыт в режиме удаленной отладки. В консоли отображается порт для подключения, копируем его и записываем его в вызове драйвера:

# Этот код нужно прописать в файле, где идет работа с Selenium

from selenium import webdriver

def setup_webdriver(port):
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_experimental_option("debuggerAddress", f"127.0.0.1:{port}")
        driver = webdriver.Chrome(options=chrome_options)
        return driver

# Указать порт
driver = setup_webdriver("Укажите порт")

Теперь при обращении к driver мы будем обращаться к Chrome, запущенному в режиме отладки. Можно выполнять любую последовательность, сколько угодно выискивать подходящие селекторы, править код в файле работы с Selenium и повторно обращаться к сессии webdriver. Можно спокойно пройти весь путь, который нужно сделать используя Selenium без перезапусков сессий и отладить процесс работы программы.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.