import asyncio import logging import os import re import time import uuid from concurrent.futures import ThreadPoolExecutor from pathlib import Path from urllib.parse import urlparse from aiogram import Bot, Dispatcher, Router, F from aiogram.filters import CommandStart from aiogram.types import Message, FSInputFile from selenium import webdriver from selenium.webdriver.firefox.options import Options from selenium.webdriver.firefox.service import Service from webdriver_manager.firefox import GeckoDriverManager TOKEN = os.getenv("BOT_TOKEN") if not TOKEN: raise RuntimeError("BOT_TOKEN env var not set") WAIT_SEC = 10 SCREEN_DIR = Path("screenshots") SCREEN_DIR.mkdir(exist_ok=True) URL_RE = re.compile(r"https?://\S+") bot = Bot(TOKEN) dp = Dispatcher() router = Router() executor = ThreadPoolExecutor(max_workers=1) def make_screenshot(url: str) -> Path: opts = Options() opts.headless = True opts.add_argument("--width=1280") opts.add_argument("--height=720") driver = webdriver.Firefox( service=Service(GeckoDriverManager().install()), options=opts, ) try: driver.get(url) time.sleep(WAIT_SEC) file_path = SCREEN_DIR / f"{uuid.uuid4()}.png" driver.get_full_page_screenshot_as_file(str(file_path)) return file_path finally: driver.quit() @router.message(CommandStart()) async def start(message: Message) -> None: await message.answer( "Привет! Пришли ссылку — я зайду на сайт, подожду 10 секунд и пришлю скриншот." ) @router.message(F.text.regexp(URL_RE)) async def handle_url(message: Message) -> None: url = message.text.strip() if not urlparse(url).scheme: await message.reply("Нужна ссылка, начинающаяся с http:// или https://") return await message.reply("Открываю страницу, подожди…") loop = asyncio.get_running_loop() file_path: Path = await loop.run_in_executor(executor, make_screenshot, url) try: photo = FSInputFile(file_path) await bot.send_photo(message.chat.id, photo, caption=f"Скриншот {url}") finally: file_path.unlink(missing_ok=True) async def main() -> None: dp.include_router(router) await bot.delete_webhook(drop_pending_updates=True) await dp.start_polling(bot) if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(name)s: %(message)s") asyncio.run(main()) Python import asyncio import logging import os import re import time import uuid from concurrent.futures import ThreadPoolExecutor from pathlib import Path from urllib.parse import urlparse from aiogram import Bot, Dispatcher, Router, F from aiogram.filters import CommandStart from aiogram.types import Message, FSInputFile from selenium import webdriver from selenium.webdriver.firefox.options import Options from selenium.webdriver.firefox.service import Service from webdriver_manager.firefox import GeckoDriverManager TOKEN = os.getenv("BOT_TOKEN") if not TOKEN: raise RuntimeError("BOT_TOKEN env var not set") WAIT_SEC = 10 SCREEN_DIR = Path("screenshots") SCREEN_DIR.mkdir(exist_ok=True) URL_RE = re.compile(r"https?://\S+") bot = Bot(TOKEN) dp = Dispatcher() router = Router() executor = ThreadPoolExecutor(max_workers=1) def make_screenshot(url: str) -> Path: opts = Options() opts.headless = True opts.add_argument("--width=1280") opts.add_argument("--height=720") driver = webdriver.Firefox( service=Service(GeckoDriverManager().install()), options=opts, ) try: driver.get(url) time.sleep(WAIT_SEC) file_path = SCREEN_DIR / f"{uuid.uuid4()}.png" driver.get_full_page_screenshot_as_file(str(file_path)) return file_path finally: driver.quit() @router.message(CommandStart()) async def start(message: Message) -> None: await message.answer( "Привет! Пришли ссылку — я зайду на сайт, подожду 10 секунд и пришлю скриншот." ) @router.message(F.text.regexp(URL_RE)) async def handle_url(message: Message) -> None: url = message.text.strip() if not urlparse(url).scheme: await message.reply("Нужна ссылка, начинающаяся с http:// или https://") return await message.reply("Открываю страницу, подожди…") loop = asyncio.get_running_loop() file_path: Path = await loop.run_in_executor(executor, make_screenshot, url) try: photo = FSInputFile(file_path) await bot.send_photo(message.chat.id, photo, caption=f"Скриншот {url}") finally: file_path.unlink(missing_ok=True) async def main() -> None: dp.include_router(router) await bot.delete_webhook(drop_pending_updates=True) await dp.start_polling(bot) if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(name)s: %(message)s") asyncio.run(main()) кидаете боту в телеграмм ссылку он открывает сайт и отправаляет скриншот сайта сделан для тех кто боится сторонних ссылок ( загружаете на сервер и пользуетесь на здоровье)