How do you send an id for items in the data base with out creating a method for each id
My goal is to type the id desired /13 and the bot returns the info I need about that item
The repo of choice is pyTelegramBotAPI
for database access and manipulation I am using flask-sqlalchemy
import telebot
from config import telegram_token
bot = telebot.TeleBot(telegram_token)
#bot.message_handler(commands=['summary'])
def send_welcome(message):
summary = """ return general info about bot performance """
bot.reply_to(message, summary )
#bot.message_handler(commands=['<id>'])
def send_welcome(message):
id_ = """ return info about this id"""
bot.reply_to(message, id_)
Your link to API shows method with regex to recognize command
#bot.message_handler(regexp="SOME_REGEXP")
which you could use with regexp="/\d+" to get any /number.
And later you should use message.text[1:] to get this number as string (without /).
#bot.message_handler(regexp="/\d+")
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
EDIT:
To run function only for /number it needs also ^ $
regexp="^/\d+$"
Without ^ $ it will run function also for hello /13 world
Minimal working code
import os
import telebot
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
bot = telebot.TeleBot(TELEGRAM_TOKEN)
#bot.message_handler(regexp="^\d+$")
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
bot.polling()
EDIT:
You can also use
#bot.message_handler(func=lambda message: ...)
like
#bot.message_handler(func=lambda msg: msg.text[0] == '/' and msg.text[1:].isdecimal())
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
or more readable
def is_number_command(message):
text = message.text
return text[0] == '/' and text[1:].isdecimal()
#bot.message_handler(func=is_number_command)
def get_id(message):
id_ = message.text[1:] # as string without `/`
#id_ = int(message.text[1:]) # as integer
bot.reply_to(message, id_)
You can use text[1:].isdecimal() or text[1:].isdigit() or text[1:].isnumeric() or str.isdecimal(text[1:]) or str.isdigit(text[1:]) or str.isnumeric(text[1:])
With func you can use other functions to make it even more complex.
Related
I am writing my first bot. The problem occurs right after send_to_club() function sends "hello". I tried to instead use a message handler with a lambda function but it didn't help either. Can you please help me find the mistake?
import telebot
from telebot import types
from scraper import get_clubs_from_search
import state
bot = telebot.TeleBot('###')
#bot.message_handler(commands=['start'])
def start(message):
msg = f"""Hello, <b>{message.from_user.first_name}</b> \n/help for commands list \n/search for search options"""
bot.send_message(message.chat.id, msg, parse_mode='html')
#bot.message_handler(commands=['help'])
def help(message):
msg = f"""You can use the following commands: \n/search to search for a team or a player"""
bot.send_message(message.chat.id, msg, parse_mode='html')
#bot.message_handler(commands=['search'])
def search(message):
markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
player_search = types.KeyboardButton("Search for a player")
team_search = types.KeyboardButton("Search for a team")
markup.add(player_search, team_search)
bot.send_message(message.chat.id, 'Choose an option:', reply_markup=markup)
#bot.message_handler(func = lambda message: message.text in ['Search for a player','Search for a team'])
def team_search(message):
if message.text == 'Search for a team':
msg = bot.send_message(message.chat.id, "Type the name of the team", reply_markup=types.ForceReply(selective=False))
bot.register_next_step_handler(msg, get_search_url)
def get_search_url(message):
"""Taking user request and forming a search url. then calling get_clubs_from_search """
search_request = message.text.split()
final_query = ""
for i in range(len(search_request)):
if i != (len(search_request)-1):
final_query += f"{search_request[i]}+"
else:
final_query += f"{search_request[i]}"
url = f"https://www.transfermarkt.com/schnellsuche/ergebnis/schnellsuche?query={final_query}"
data = get_clubs_from_search(url)
bot.register_next_step_handler(message, return_search(message, data))
def return_search(message, data):
"""Presenting dataframe to user and asking to choose a team"""
msg = "Please choose the team:\n\n"
markup = types.ReplyKeyboardMarkup(True)
for i in range(len(data)):
msg += f"""{i+1}. {data.loc[i]['club_names']} from {data.loc[i]['country_names']}\n"""
markup.add(types.KeyboardButton(i+1))
final_message = bot.send_message(message.chat.id, msg, reply_markup=markup)
bot.register_next_step_handler(final_message, send_to_club_page, data)
This is where the problem occurs. Both this method and using a message_handler lead to the same error and break the bot. It seems no different to the way I registered message handlers above, and those work just fine
def send_to_club_page(message, data):
msg = "hello"
bot.send_message(message.chat.id, msg, parse_mode='html')
while True:
bot.polling(none_stop=True, timeout=5)
Ok. So the correct answer was given to me by Tim Roberts in the comments.
The problem was with me not passing the function object and instead calling it. The NoneType object is the return of the function return_search. I was supposed to pass the function object like this: bot.register_next_step_handler(message, return_search, data)
Thank you very much for your criticism about the error message too. I will make sure to post more well-thought questions in the future
I'm trying to create a python telegram bot that send random news every x time, and it works when i give the method news() the chat_id statically directly on the method, I tried passing it directly on the method start(), that execute a run_repeating job like that:
def start():
context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
but after you run the command for the first time (and works) it trows a lot of errors.
Instead I hardcoded the chat_id inside the news() method.
Anyone has any hint on how could I pass the variable update to the news() method?
Here's my full code:
from dotenv import load_dotenv
import telegram.ext
import requests
import datetime
import random
import json
import os
load_dotenv()
token = os.getenv('TOKEN')
api = os.getenv('API')
languages = "en"
newsTimer = 600
query = "world"
pageSize = "100"
yesterday = str(datetime.datetime.now() - datetime.timedelta(days=1))
today = str(datetime.datetime.now())
api_url = "https://newsapi.org/v2/everything?q=" + query + "&from=" + yesterday + "&to=" + today + "&sortBy=popularity&pageSize=+"+ pageSize +"&apiKey=" + api
def start(update, context):
context.job_queue.run_repeating(news, interval=newsTimer, first=1)
def help(update, context):
update.message.reply_text("""
Available commands:
/start - start bot
/help - help
""")
def news(context):
response = requests.get(api_url)
json_data = json.loads(response.text)
i = random.randint(0, 99)
title = json_data['articles'][i]['title']
image = json_data['articles'][i]['urlToImage']
description = json_data['articles'][i]['description']
author = json_data['articles'][i]['author']
article = json_data['articles'][i]
if title is None:
title = "No title"
if image is None:
image = "https://www.alfasolare.ru/a_solar_restyle/wp-content/themes/consultix/images/no-image-found-360x260.png"
if description is None:
description = "No Content"
if author is None:
author = "No Author"
if article is None:
i = random.randint(0, len(json_data['articles']))
caption = "<a>" + title + "\n" + description + "\n Author: " + author + "</a>"
chat_id = "XXXXXXXXX" #my own chat id
context.bot.send_photo(
chat_id=chat_id,
photo=image,
caption=caption,
parse_mode=telegram.ParseMode.HTML
)
if __name__ == '__main__':
updater = telegram.ext.Updater(token, use_context=True)
dispatcher = updater.dispatcher
dispatcher.add_handler(telegram.ext.CommandHandler('start', start))
dispatcher.add_handler(telegram.ext.CommandHandler('help', help))
if updater.start_polling():
print("Bot started successfully!")
if updater.idle():
print("Bot stopped")
context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
this can't work since the callback argument of JobQueue.run_* must be a function. However, news(update=update, context=context) is the return value of that function call, which is None as news doesn't return anything.
To pass additional data to the job callback, you can use the context argument of JobQueue.run_*. This is also explained in PTBs wiki page on JobQueue and showcased in the timerbot.py example.
Disclaimer: I'm currently the maintainer of python-telegram-bot
I have this welcome bot for telegram from github. I would like that every time a new user joins the group in addition to sending him the message it was mentioned and reply to "id has join in group" as the classic group help does.
I attach below the code to work on:
#run_async
def send_async(context, *args, **kwargs):
context.bot.send_message(*args, **kwargs)
def check(update, context, override_lock=None):
"""
Perform some checks on the update. If checks were successful, returns True,
else sends an error message to the chat and returns False.
"""
chat_id = update.message.chat_id
chat_str = str(chat_id)
if chat_id > 0:
send_async(
context, chat_id=chat_id, text="Please add me to a group first!",
)
return False
locked = override_lock if override_lock is not None else db.get(chat_str + "_lck")
if locked and db.get(chat_str + "_adm") != update.message.from_user.id:
if not db.get(chat_str + "_quiet"):
send_async(
context,
chat_id=chat_id,
text="Sorry, only the person who invited me can do that.",
)
return False
return True
# Welcome a user to the chat
def welcome(update, context, new_member):
""" Welcomes a user to the chat """
message = update.message
chat_id = message.chat.id
logger.info(
"%s joined to chat %d (%s)",
escape(new_member.first_name),
chat_id,
escape(message.chat.title),
)
# Pull the custom message for this chat from the database
text = db.get(str(chat_id))
# Use default message if there's no custom one set
if text is None:
text = "Hello $username! Welcome to $title 😊"
# Replace placeholders and send message
text = text.replace("$username", new_member.first_name)
text = text.replace("$title", message.chat.title)
send_async(context, chat_id=chat_id, text=text, parse_mode=ParseMode.HTML)
this is the result I would like to achieve.
would anyone know how to help me in this simple task? Thank you!
it's complicated code... keep it simple.
you have an event in group "new chat members". so handle this event and send reply with first_name and link to the account.
Pyrogram example:
from pyrogram import Client
from pyrogram import filters
ACCOUNT = '77777777777'
config = 'config.ini'
__client = Client(session_name=ACCOUNT, config_file=config)
def user_link(user):
USER_LINK = '{first_name} : #{username}'
USERID_LINK = '{first_name} : {id}'
return USER_LINK.format(**user.__dict__) if user.username else USERID_LINK.format(**user.__dict__)
#__client.on_message(filters.new_chat_members)
def welcome(client, message):
users = ", ".join([user_link(message.from_user.__dict__) for m in message.new_chat_members])
message.reply(f"Hello, {users}")
This is the first script which get's data from a website:
import requests
def get_prices():
name = "SeedifyFund"
crypto_data = requests.get("https://api.pancakeswap.info/api/tokens").json()["data"]
data = None
for i in crypto_data:
current = crypto_data[i]
if current['name'] == name:
data = {
"PriceUSD": current["price"],
"PriceBNB": current["price_BNB"],
}
return data
if __name__ == "__main__":
print(get_prices())
The code above outputs the following: {'PriceUSD': '1.022239219137518991087869433174527', 'PriceBNB': '0.002452203037583603303073246037795846'}
I'm having issue an issue with the second script. I want it to use the data that it has collected above and print it in a telegram bot when the user types /price. The code for the second script:
import telegram
from telegram.ext import Updater
from telegram.ext import CommandHandler
from tracker import get_prices
telegram_bot_token = "API TOKEN"
updater = Updater(token=telegram_bot_token, use_context=True)
dispatcher = updater.dispatcher
def price(update, context):
chat_id = update.effective_chat.id
message = ""
crypto_data = get_prices()
for i in crypto_data:
bnbprice = crypto_data[i]["pricebnb"]
usdprice = crypto_data[i]["priceusd"]
message += f"1 SFUND = \n${usdprice:,.2f} USD\n{bnbprice:.3f} BNB\n\n"
context.bot.send_message(chat_id=chat_id, text=message)
dispatcher.add_handler(CommandHandler("price", price))
updater.start_polling()
When the user types /price in the telegram chat it give this error:
coin = crypto_data[i]["pricebnb"]
TypeError: string indices must be integers
Could someone tell me what I'm doing wrong and help me solve the issue. Many thanks
When trying to sendMessage it tells me the chat id is not defined. I am able to answerCallbackQuery because it needs query ID not chat.
If I try to enter in 'chat_id' in the DEF on callback query area it throws up more errors
Where exactly in the code do I need to define it?
import sys
import time
import os
import telepot
from telepot.loop import MessageLoop
from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton
def on_chat_message(msg):
content_type, chat_type, chat_id = telepot.glance(msg)
#creating buttons
if content_type == 'text':
if msg['text'] == '/start':
bot.sendMessage(chat_id, 'Welcome to #UK_Cali Teleshop\n Created by JonSnow 2021',reply_markup = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Feedback",callback_data='a'), InlineKeyboardButton(text="You",callback_data='b'),InlineKeyboardButton(text="PGP",callback_data='c'), InlineKeyboardButton(text="Cunt",callback_data='d')],
[InlineKeyboardButton(text="Products",callback_data='e')]
]
))
def on_callback_query(msg):
query_id, from_id, query_data = telepot.glance(msg, flavor='callback_query')
print('Callback Query:', query_id, from_id, query_data)
#find callback data
if query_data == 'a':
#bot.sendMessage(chat_id, 'dsuhsdd')
#answerCallbackQuery puts the message at top
bot.answerCallbackQuery(query_id, 'products')
bot = telepot.Bot('1646167995:AAGsOwfjcryYYkoah69QJ6XGA7koUywmuRk')
MessageLoop(bot, {'chat': on_chat_message,
'callback_query': on_callback_query}).run_as_thread()
print('Listening ...')
while 1:
time.sleep(10)
The chat_id variable is local to on_chat_message. on_callback_query does not have access to it. The most Pythonic method would make these into a class and store the chat id in a member variable, but you can do it here by adding
global chat_id
as the first line of on_chat_message. You don't need that in on_callback_query because you aren't changing the value, although it won't hurt.