Я использую приведенный ниже код для входа в учетную запись продавца TikTok. Но он работает на Mac корректно даже в безголовом режиме. Когда я запускаю его внутри Docker, я получаю следующую ошибку.
ERROR:setup:Попытка входа 3 не удалась: Сообщение: элемент не взаимодействуем
Код для входа в учетную запись продавца TikTok:
from selenium.webdriver.common.by import By
import undetected_chromedriver as uc
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
import logging
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
logger = logging.getLogger('setup')
def setup_driver(profile_id=None):
# Инициализация опций Chrome
options = uc.ChromeOptions()
# Опционально: Укажите местоположение двоичного файла явно, если это необходимо (раскомментируйте и обновите этот путь по мере необходимости)
# options.binary_location = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" # Для macOS
options.binary_location = "/usr/bin/google-chrome" # Для Linux/Docker окружений
# Установка параметров Chrome для лучшего опыта автоматизации
options.add_argument("--start-maximized") # Открыть браузер в максимальном размере
options.add_argument("--disable-popup-blocking") # Отключить любые всплывающие окна, которые могут прерывать
options.add_experimental_option("prefs", {
"profile.default_content_setting_values.popups": 1,
"profile.default_content_setting_values.notifications": 1
})
# Дополнительные параметры Chrome для оптимизации производительности и стабильности
options.add_argument("--disable-background-networking")
options.add_argument("--disable-background-timer-throttling")
options.add_argument("--disable-backgrounding-occluded-windows")
options.add_argument("--disable-breakpad")
options.add_argument("--disable-client-side-phishing-detection")
options.add_argument("--disable-default-apps")
options.add_argument("--disable-hang-monitor")
options.add_argument("--disable-prompt-on-repost")
options.add_argument("--disable-sync")
options.add_argument("--metrics-recording-only")
options.add_argument("--no-first-run")
options.add_argument("--safebrowsing-disable-auto-update")
options.add_argument("--password-store=basic")
options.add_argument("--use-mock-keychain")
options.add_argument("--disable-infobars") # Отключить раздражающие информационные панели в Chrome
options.add_argument("--disable-blink-features=AutomationControlled") # Избежать обнаружения как бота
options.add_argument("--no-sandbox") # Исправить проблемы в некоторых окружениях
options.add_argument("--disable-dev-shm-usage") # Решить проблемы с ресурсами
options.add_argument("--disable-gpu") # Отключить аппаратное ускорение
options.add_argument("--remote-debugging-port=9222") # Избежать конфликтов портов
# Раскомментируйте эту строку, чтобы запустить в безголовом режиме (для серверных или Docker окружений)
options.add_argument("--headless")
try:
if profile_id:
base_profile_dir = os.path.join(os.getcwd(), "chrome_profiles")
profile_path = os.path.join(base_profile_dir, f"profile_{profile_id}")
# Проверьте, существует ли профиль; если он существует, загружаем его, иначе создаем
if not os.path.exists(profile_path):
logger.info(f"Директория профиля для {profile_id} не существует, создается...")
os.makedirs(profile_path, exist_ok=True)
else:
logger.info(f"Директория профиля для {profile_id} уже существует, загружается...")
# Используйте определенный профиль Chrome
options.add_argument(f"--user-data-dir={profile_path}")
# Инициализация драйвера Chrome с определенными параметрами
driver = uc.Chrome(service=Service(ChromeDriverManager().install()), options=options)
return driver
except Exception as e:
logger.error(f"Не удалось настроить драйвер Chrome: {e}")
print(f"Не удалось настроить драйвер Chrome: {e}", flush=True)
return None
def login_to_tiktok(driver, email, password, max_retries=3):
# Открываем страницу входа продавца TikTok
driver.get("https://seller-us-accounts.tiktok.com/account/login")
# Ждем и нажимаем на вкладку 'Email', чтобы переключиться на вход по электронной почте, если она еще не выбрана
email_tab = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'tab')]//span[text()='Email']"))
)
if email_tab.is_selected():
print("Вкладка электронной почты уже выбрана")
else:
email_tab.click()
logger.info("Вход в учетную запись продавца TikTok...")
print("Вход в учетную запись продавца TikTok...", flush=True)
# Ждем, чтобы поле ввода электронной почты стало видимым и доступным для взаимодействия
email_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//input[@placeholder='Введите ваш адрес электронной почты']"))
)
email_input.clear()
email_input.send_keys(email)
logger.info("Электронная почта введена")
print("Электронная почта введена", flush=True)
# Ждем, чтобы поле ввода пароля стало доступным для взаимодействия
password_input = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//input[@placeholder='Введите ваш пароль']"))
)
password_input.clear()
password_input.send_keys(password)
logger.info("Пароль введен")
print("Пароль введен", flush=True)
# Нажимаем кнопку входа
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'Войти')]"))
)
login_button.click()
logger.info("Кнопка входа нажата")
print("Кнопка входа нажата", flush=True)
# Ждем завершения процесса входа, проверяя наличие элемента после входа (например, панель управления пользователя)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#dashboard_element_selector")) # Обновите этот селектор
)
logger.info("Успешно вошли в систему")
return True # Вход выполнен успешно, выходим из цикла
def login_sellers_with_profile(self):
email = self.email
password = self.password
driver = setup_driver(profile_id=email)
# Проверяем, вошел ли пользователь в систему, посетив главную страницу
if self.is_logged_in(driver):
logger.info(f"✋ ✋ ✋ {email} уже вошел в систему, пропускаем вход.")
print(f"✋ ✋ ✋ {email} уже вошел в систему, пропускаем вход.", flush=True)
return driver
logger.info(f"🧐 🧐 🧐 Вход для {email}...")
print(f"🧐 🧐 🧐 Вход для {email}...", flush=True)
# Если не вошел в систему, выполняем процесс входа
login_response = login_to_tiktok(driver, email, password)
print(f"🔑 🔑 🔑 Ответ при входе: {login_response}", flush=True)
if login_response:
logger.info(f"✔ ✔ ✔ Успешно вошли в систему для {email}")
print(f"✔ ✔ ✔ Успешно вошли в систему для {email}", flush=True)
else:
logger.info(f"✘ ✘ ✘ Вход не удался для {email}")
print(f"✘ ✘ ✘ Вход не удался для {email}", flush=True)
driver.quit()
return None
return driver
Я использую Docker внутри виртуальной машины Linux для входа в систему. Я получаю следующую ошибку. Я также поделился кодом настройки драйвера.
Дайте знать, если потребуется что-то еще.
Ответ
Чтобы решить проблему, с которой вы столкнулись при использовании Selenium для входа в аккаунт TikTok Seller в Docker, и поскольку ошибка "element not interactable" указывает на то, что элемент, с которым вы пытаетесь взаимодействовать (например, поле ввода или кнопка), недоступен для взаимодействия, можно попробовать несколько подходов для устранения данной проблемы.
Вот несколько рекомендаций и улучшений к вашему коду:
1. Убедитесь, что элементы загружены
Иногда элементы могут загружаться медленно или их визуальное состояние может изменяться. Убедитесь, что вы используете правильные ожидания для того, чтобы убедиться, что элементы действительно доступны для взаимодействия.
2. Использование более надежных селекторов
Убедитесь, что ваши XPath селекторы правильные. Попробуйте использовать более устойчивые селекторы, например, по ID или более конкретный class.
3. Клик по элементам
Иногда элемент может быть скрыт или размещен под другим элементом. Убедитесь, что перед тем, как кликать по элементу, он действительно доступен и виден. Добавьте явные ожидания для отображения элемента:
from selenium.webdriver.common.action_chains import ActionChains
# Пример кликания с использованием ActionChains
ActionChains(driver).move_to_element(email_tab).click().perform()
4. Возможные временные задержки
Возможно, в среде Docker время загрузки больше, чем на вашем Mac. Попробуйте увеличить время ожидания для элементов:
email_input = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//input[@placeholder='Enter your email address']"))
)
5. Отладка
Запускайте браузер в ненадежном режиме, чтобы видеть, что происходит в самом браузере, даже если вы работаете в Docker. Вы можете оставить параметр:
options.add_argument("--headless") # Комментируйте эту строку для отладки
Полный исправленный пример:
Вот ваш обновленный код с некоторыми предложенными улучшениями:
def login_to_tiktok(driver, email, password, max_retries=3):
driver.get("https://seller-us-accounts.tiktok.com/account/login")
# Явное ожидание для выбора "Email" таба
email_tab = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'tab')]//span[text()='Email']"))
)
if not email_tab.is_selected():
email_tab.click()
logger.info("Logging in to TikTok Seller account...")
# Ожидание email-инпута
email_input = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//input[@placeholder='Enter your email address']"))
)
email_input.clear()
email_input.send_keys(email)
logger.info("Email entered")
# Ожидание password-инпута
password_input = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//input[@placeholder='Enter your password']"))
)
password_input.clear()
password_input.send_keys(password)
logger.info("Password entered")
# Ожидание кнопки логина
login_button = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'Log in')]"))
)
login_button.click()
logger.info("Login button clicked")
# Проверка успешного входа
WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#dashboard_element_selector")) # Обновите селектор
)
logger.info("Logged in successfully")
return True
Попробуйте запустить этот код внутри Docker и посмотрите, решит ли это вашу проблему. Если ошибки все еще возникают, рассмотрите возможность добавления дополнительных логов для диагностики.