I'm trying to create a telegram bot that can send a screenshot of a web page.
I'm using python-telegram-bot to handle telegram interactions and python-playwright to get screenshots of a page. The problem with my code is that i get the following error with Playwright:
greenlet.error: cannot switch to a different thread
This happens because i'm declaring browser = p.chromium.launch(headless=True, args=args)
outside of the function that gets executed when a telegram command is called. The problem is that launching the browser every time the telegram command is called, slows my code down for about 3 seconds. How can i declare browser
globally? Is it even possible?
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ParseMode
from telegram.ext import Updater, CommandHandler, ChatMemberHandler, CallbackQueryHandler
from telegram.error import Unauthorized, BadRequest
from playwright.sync_api import sync_playwright
args = [
"--no-sandbox",
"--disable-setuid-sandbox",
"--use-gl=egl",
]
p = sync_playwright().start()
browser = p.chromium.launch(headless=True, args=args)
def start(update, context):
page = browser.new_page()
page.goto("https://google.com")
page.screenshot(path="example.png")
page.close()
context.bot.send_photo(chat_id=update.effective_chat.id, photo=open("example.png", "rb"))
updater = Updater('TOKEN', use_context=True, workers=124)
updater.dispatcher.add_handler(CommandHandler('start', start, run_async=True))
updater.start_polling()
updater.idle()
I have worked on it, and I have changed a lot in your code,
I have made a bot to try until I finish it successfully.
I have changed the code into async code.
this is the last code:
import telegram
from telegram import Update
from telegram.ext import MessageHandler, CommandHandler, Application, ContextTypes, filters
from playwright.async_api import async_playwright
args = [
"--no-sandbox",
"--disable-setuid-sandbox",
"--use-gl=egl",
]
# Replace 'YOUR_API_TOKEN' with the API token you received from BotFather.
API_TOKEN = 'yours'
async def download_screan_shot(link="www.google.com", id_of_chat=None, update_to_use_it_to_send_the_file=None):
file_name =f"{id_of_chat}_example.png"
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto(link)
await page.screenshot(path=file_name)
await browser.close()
await update_to_use_it_to_send_the_file.message.reply_photo(file_name)
async def messages(update, context):
the_gotten_message = update.message.text
if "www" in the_gotten_message:
await download_screan_shot(link=the_gotten_message, id_of_chat=update.message.from_user.id, update_to_use_it_to_send_the_file=update)
else:
await update.message.reply_text(update.message.text)
app = Application.builder().token(API_TOKEN).build()
app.add_handler(MessageHandler(filters.TEXT,messages))
app.run_polling()
and this is a screenshot from my bot:
I hope it works for you.
about the amount of sent links, these are failed tries.
because you have said that you want to run the browser once, I did not find any solution for that, but I have done it using a bad idea.
it runs the browser once then saves it in public inside a list, and then uses that active browser.
this is my new code :
import telegram
from telegram import Update
from telegram.ext import MessageHandler, CommandHandler, Application, ContextTypes, filters
from playwright.async_api import async_playwright
from playwright.sync_api import sync_playwright
args = [
"--no-sandbox",
"--disable-setuid-sandbox",
"--use-gl=egl",
]
# Replace 'YOUR_API_TOKEN' with the API token you received from BotFather.
API_TOKEN = 'yours'
opened_browser = []
async def download_screan_shot(link="www.google.com", id_of_chat=None, update_to_use_it_to_send_the_file=None):
file_name =f"{id_of_chat}_example.png"
# playwright = sync_playwright().start()
# browser = playwright.chromium.launch()
# page = browser.new_page()
# page.goto("https://playwright.dev/")
# page.screenshot(path="example.png")
# browser.close()
if (not opened_browser):
playwright = await async_playwright().start()
browser = await playwright.chromium.launch()
opened_browser.append(browser)
page = await opened_browser[0].new_page()
await page.goto(link)
await page.screenshot(path=file_name)
await page.close()
# await opened_browser[0].close()
await update_to_use_it_to_send_the_file.message.reply_photo(file_name)
async def messages(update, context):
the_gotten_message = update.message.text
if "www" in the_gotten_message:
await download_screan_shot(link=the_gotten_message, id_of_chat=update.message.from_user.id, update_to_use_it_to_send_the_file=update)
else:
await update.message.reply_text(update.message.text)
app = Application.builder().token(API_TOKEN).build()
app.add_handler(MessageHandler(filters.TEXT,messages))
app.run_polling()
to be honest with you, I have not seen any difference in the performance, and also I do not know what is happening there.
it is just a try, to give you an idea.
you can do the same in your code >>> I did not do that because I think you are using an old version of telegram library, and for that, I faced many errors when I tried your code with the version that I have.
tell me.