телеграмм-бот с selenum на сервере

Всем привет.

Стэк: Python 3.11, selenium-stealth, aiogram.

При разработке ТГ бота для парсинга сайта я столкнулся с проблемой в работоспособности скрипта. На моем компьютере программа работает без нареканий, но при выгрузке на сервер она отказывается работать должным образом. При нажатии на кнопку "Старт", программа не запускает chromedriver и не осуществляет парсинг.

При этом, однажды программа все таки заработала на сервере. Это было удивлением для меня, потому что я вообще не запускал код, просто перезапустил проект. Я осуществлял запуск скрипт на деплой хостинге Amvera, а также на арендованном VPS. Везде программа не выдает никаких логов об ошибке, хотя я прописал декоратор, который должен выводить информацию об ошибке.

На сервере запускаю файл new.py, который отвечает за работу телеграмм-бота.

main.py:

def ex(func):
    async def show_ex(*args, **kwargs):
        try:
            await func(*args, **kwargs)
        except Exception as e:
            print('Ошибка: ', e)
    return show_ex

@ex
async def process_user(user_id, products):
    conn = await aiosqlite.connect('test.db')  # Подключаемся к базе данных асинхронно
    async with conn.cursor() as cursor:

        tasks = []
        for product_key, product_value in products.items():
            table_exists = await check_table_exists(conn, product_value)
            if not table_exists:
                await create_table(cursor, product_value.replace(" ", ''))

            url = f'https://example.com'
            task = asyncio.create_task(process_product(user_id, cursor, product_value, url))
            tasks.append(task)

        await asyncio.gather(*tasks)

        await conn.commit()

@ex
async def process_product(user_id, cursor, product_value, url):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-gpu")
    options.add_argument("--remote-debugging-port=9230")
    service = Service(executable_path="/home/test/chromedriver")
    driver = webdriver.Chrome(service=service, options=options)
    try:
        driver.maximize_window()
        driver.get(url)

        card_divs = driver.find_elements(By.XPATH, '//li[@class="sc-bcd1c877-2 gWHcGv"]')[:10]
        for card_div in card_divs:
            try:
                new_price = float(
                    (card_div.find_element(By.TAG_NAME, 'span').text.replace('¥', '').replace(' ', '').replace(',', '').
                     replace('\n', '')))
            except ValueError:
                new_price = 'СКИДКА'
            except selenium.common.exceptions.NoSuchElementException:
                new_price = '?'
            link = card_div.find_element(By.TAG_NAME, 'a').get_attribute('href')
            img = card_div.find_element(By.TAG_NAME, 'img').get_attribute('src')
            await insert_data(cursor, product_value, new_price, link, img)
            print(new_price, link, img)
            card = (f"Товар: {link} \n"
                    f"Цена: {new_price} руб.\n")
            if card:
                await send_product_messages(user_id, card, img)
            else:
                print('Товаров нет')
                await bot.send_message(user_id, 'Товаров нет')
    finally:
        driver.stop_client()
        driver.close()
        driver.quit()

new.py :

tracemalloc.start()

async def run_periodic(user_id, products):
    while True:
        await process_user(user_id, products)
        await asyncio.sleep(300)


@dp.message_handler(Text(equals="Запуск"))
@rights
async def run_program(message: types.Message):
    await message.answer("Программа запущена")

    user_id = str(message.from_user.id)

    with open('users.json', 'r', encoding='utf-8') as file:
        users = json.load(file)

    if 'Товары' not in users[user_id]:
        await message.answer("У Вас нет товаров для запуска программы.")
        return

    asyncio.create_task(run_periodic(user_id, users[user_id]['Товары']))

Ответы (1 шт):

Автор решения: Maxim

Облако Амвера использует под капотом контейнеры. Чтобы было возможно использовать selenium в контейнере, надо поставить необходимые библиотеки и указать порт дисплея:

ENV DISPLAY=:99

Есть уже готовые образы python с selenium, например: joyzoursky/python-chromedriver

Таким образом, Dockerfile может быть следующим:

FROM joyzoursky/python-chromedriver:3.9-selenium

ENV PYTHONUNBUFFERED=1 # прокидываем логи из консоли

WORKDIR /app
COPY requirements.txt /app
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "main.py"]
→ Ссылка