Загрузка данных
from dataclasses import dataclass
from typing import Optional, Tuple
import logging
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import (
TimeoutException,
WebDriverException,
NoSuchElementException,
ElementClickInterceptedException,
)
Locator = Tuple[str, str]
@dataclass(frozen=True)
class StickerBotConfig:
chat_url: str
sticker_button: str # CSS selector кнопки со стикерами
sticker_item: str # CSS selector нужного стикера
send_button: Optional[str] = None # если нужен отдельный шаг "Отправить"
timeout: int = 20
class StickerSender:
def init(self, config: StickerBotConfig, headless: bool = False):
self.config = config
self.logger = logging.getLogger(self.class.name)
options = Options()
if headless:
options.add_argument("--headless=new")
options.add_argument("--window-size=1280,900")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
# Если chromedriver уже в PATH, Service() можно не указывать.
self.driver: WebDriver = webdriver.Chrome(options=options)
self.wait = WebDriverWait(self.driver, self.config.timeout)
def enter(self):
return self
def exit(self, exc_type, exc, tb):
self.close()
def open_chat(self) -> None:
self.driver.get(self.config.chat_url)
self._wait_for_page_ready()
def send_sticker(self) -> bool:
try:
self._click((By.CSS_SELECTOR, self.config.sticker_button), "кнопка стикеров")
self._click((By.CSS_SELECTOR, self.config.sticker_item), "стикер")
if self.config.send_button:
self._click((By.CSS_SELECTOR, self.config.send_button), "кнопка отправки")
self.logger.info("Стикер успешно отправлен.")
return True
except TimeoutException:
self.logger.error("Не удалось дождаться нужного элемента на странице.")
except (WebDriverException, NoSuchElementException, ElementClickInterceptedException) as e:
self.logger.error("Ошибка отправки стикера: %s", e)
return False
def close(self) -> None:
if getattr(self, "driver", None):
self.driver.quit()
def _wait_for_page_ready(self) -> None:
self.wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
def _click(self, locator: Locator, name: str) -> None:
element = self.wait.until(EC.element_to_be_clickable(locator))
self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
try:
element.click()
except ElementClickInterceptedException:
# На случай перекрытия элементом-оверлеем
self.driver.execute_script("arguments[0].click();", element)
self.logger.debug("Нажата %s.", name)
if name == "main":
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
config = StickerBotConfig(
chat_url="https://example.com/chat",
sticker_button="button.stickers",
sticker_item='div[data-sticker-id="123"]',
send_button=None,
timeout=20,
)
with StickerSender(config, headless=False) as bot:
bot.open_chat()
bot.send_sticker()