#python #selenium #google-chrome #selenium-webdriver #selenium-chromedriver
#python #selenium #google-chrome #selenium-webdriver #selenium-chromedriver
Вопрос:
Я разработал приложение python для Selenium с использованием Chrome / ChromeDriver. Приложение, похоже, довольно хорошо работает на моем ноутбуке под управлением Windows, но когда я переношу все на свой серверный компьютер под управлением Linux, я начал замечать странное поведение при параллельном запуске нескольких экземпляров браузера.
Подход, который я использую в настоящее время, довольно прост: у меня есть один демон, запускающий отдельный экземпляр процесса с Popen для каждого подпроцесса следующим образом:
sub_call = subprocess.Popen(["python", "my_script.py"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, text=True, universal_newlines=True)
В идеале каждый подпроцесс должен выполняться параллельно в отдельном сеансе Chrome со своими собственными параметрами браузера (cookies, прокси и т. Д.).
Механизмы синхронизации не реализованы ни в одном вспомогательном процессе.
На данный момент я бы предпочел избегать Selenium Grid, потому что я планирую запускать только несколько экземпляров параллельно (скажем, менее 5), и у меня есть аппаратные ограничения, связанные со всем, что работает в Docker на NAS.
Это код, который я использую для создания экземпляра каждого объекта ChromeDriver:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_argument('--user-agent={}'.format(constants.BROWSER_AGENT_HEADER))
chrome_options.add_argument("--headless")
#chrome_options.add_argument("--remote-debugging-port={}".format(CHROME_DRIVER_DEBUG_PORT))
chrome_options.add_argument("--window-size={}".format(CHROME_DRIVER_RESOLUTION))
if ON_POSIX:
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# chrome_options.add_argument('--remote-debugging-address={}'.format(CHROME_DRIVER_DOCKER_BIND))
chrome_options.add_argument('--proxy-server=http://{}:{}'.format(self.proxy_ip, self.proxy_port))
cap = webdriver.DesiredCapabilities.CHROME
cap['proxy'] = {
"httpProxy": proxy_address_str,
"httpsProxy": proxy_address_str,
"ftpProxy": proxy_address_str,
"sslProxy": proxy_address_str,
"proxyType": "MANUAL",
}
cap['goog:loggingPrefs'] = {'performance': 'ALL'}
service_args = ["--log-path={}/chromedriver.log".format(LOGFILE_PATH),
"--whitelisted-ips=", "--profile-directory={}".format(username)]
self.driver = webdriver.Chrome(executable_path=constants.CHROME_DRIVER_PATH,
service_args=service_args, desired_capabilities=cap, options=chrome_options)
Где я попытался разделить каждую пользовательскую среду с помощью аргумента —profile-directory (ПРИМЕЧАНИЕ: я просто ввел свои системные имена пользователей, фактически не настраивая профиль Chrome)
Однако кажется, что в то время как в Windows каждый процесс открывает свое собственное окно Chrome, в Linux есть конфликты. Основная проблема, с которой я столкнулся, заключается в том, что когда процесс завершается, если он выполняет только одну из приведенных выше строк, это каким-то образом влияет на браузер других процессов:
driver.quit()
driver.close()
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL 'w')
Я временно прокомментировал каждую из приведенных выше строк. Кажется, он работает отлично (10 часов работы в обычном режиме, никаких проблем)
Теперь меня беспокоит то, что я хочу избежать того, чтобы все открытые экземпляры Chrome в конечном итоге получили всю мою память.
Как я могу очистить браузер, не затрагивая другие запущенные процессы?
Заранее благодарю вас за любую поддержку, которую я получу.
Комментарии:
1. показать код, который устанавливает CHROME_DRIVER_DEBUG_PORT (и вашу многопоточность)
2. спасибо @pcalkins, я только что добавил запрошенные данные. Обратите внимание, что я: 1) добавил service_args, как указано выше; 2) удален из порта отладки, чтобы избежать каких-либо помех привязки (это все равно не работает, поскольку при переходе по ссылке на страницу, которая обычно появляется на главной странице отладки, появляется пустая страница, но это уже другая история, и я подумываю о том, чтобы осветить это специальным сообщением). Все еще возникают проблемы. 🙁
3. вам не нужно устанавливать каталог профиля. Это создаст новый временный профиль для каждого потока. Вы все еще не показали, как вы передаете переменные… но тот факт, что он работает на одной ОС, а не на другой, указывает на проблемы с путями.
4. @pcalkins не могли бы вы поделиться более подробной информацией, пожалуйста? —лог-путь работает правильно (у каждого процесса есть свой специальный журнал), CHROME_DRIVER_PATH является константой. Все пути к Selenium / Chromedriver / Chrome являются константами. Я предполагаю, что если они работают для одного процесса, то они будут работать для любого размера пула процессов.
5. @pcalkins Что касается каталога профилей, это просто тест для обеспечения изоляции между каждым запущенным процессом и связанными с ним пользователями. (Это соответствующее требование моего кода, чем больше каждый процесс разделен, тем лучше). Пользователи перерабатываются, но настройка каждого профиля вручную была бы слишком дорогой (я работаю с выборкой из 100 пользователей). Есть ли лучшие варианты?