本文旨在分享搭建一个获取当日信号传输预测的Telegram Bot,不支持用来实施违法犯罪行为
前言:感谢 huige(@huige233) , acolaen (@nealoca) ,Neo_Chen(BU4AK)(@Neo_Chen) 在搭建此Bot时的帮助,也感谢友站ibcl博主为本人提供了搭建Telegram Bot来获取当日传播预测的想法
一、传播预测图的获取
作为一名HAM,每日信号传播的预测对于选一个好的波段来与友台通联是十分重要的,然而我们无法做到像各个气象局那样能够直接从卫星获得图像来分析当日传播情况,也没有那个时间,所以我们只能靠着别人每日更新的方式来获得传播预测图
那么经过Google,我们有以下两个方式来获得当日的传播预测
第一种:来自 www.hamqsl.com 上的每日传播预测图
以下是其提供的服务列表及其地址:
HF & VHF Selectable SN Selectable 304A Band Condition Calculations EME Deg Selectable MUF Horizontal Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solarn0nbh.php |
No Band Condition Calculations Large Vertical Selectable 304A 19 Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solarpic.php |
HF & VHF Band Condition Calculations Large Vertical Selectable 304A EME Deg Selectable MUF Black Only No Transparent | https://www.hamqsl.com/solarvhf.php |
No Band Condition Calculations Small Vertical Selectable 304A Multi-Color & Transparent | https://www.hamqsl.com/solar.php |
No Band Condition Calculations Small Vertical Selectable 304A Multi-Color & Transparent | https://www.hamqsl.com/solarsmall.php |
No Band Condition Calculations Small Vertical Limited Data Multi-Color & Transparent | https://www.hamqsl.com/solarbrief.php |
Only Band Condition Calculations Small Vertical Multi-Color & Transparent | https://www.hamqsl.com/solarbc.php |
Band Condition Calculations Small Vertical Selectable 304A Multi-Color & Transparent | https://www.hamqsl.com/solar100sc.php |
Band Condition Calculations Large Vertical Selectable 304A Multi-Color & Transparent | https://www.hamqsl.com/solar2.php |
No Band Condition Calculations Horizontal Selectable 304A 19 Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solarpich.php |
Band Condition Calculations Selectable Europe K-Ind tromso & dombas Selectable 304A 19 Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solar101pic.php |
HF & VHF Selectable Europe K-Ind tromso & dombas Selectable 304A Band Condition Calculations EME Deg Selectable MUF Horizontal Black Only No Transparent | https://www.hamqsl.com/solar101vhf.php |
HF & VHF Selectable Europe K-Ind tromso & dombas Selectable 304A Band Condition Calculations EME Deg Selectable MUF Horizontal Black Only No Transparent | https://www.hamqsl.com/solar101vhfper.php |
HF & VHF Selectable Europe K-Ind tromso & dombas Selectable 304A Band Condition Calculations EME Deg Selectable MUF Horizontal 19 Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solar101vhfpic.php |
Band Condition Calculations Selectable Europe K-Ind tromso & dombas Selectable 304A Multi-Color & Transparent | https://www.hamqsl.com/solar101sc.php |
No Band Condition Calculations Horizontal Selectable 304A 19 Selectable Solar Images Black Only No Transparent | https://www.hamqsl.com/solarsun.php |
No Band Condition Calculations Horizontal 304A @ EVE only Solar Flux Sunspot No. Graph Last 30 days Black Only No Transparent | https://www.hamqsl.com/solargraph.php |
No Band Condition Calculations Horizontal 171A & 304A @ EVE only Solar Flux Sunspot No. 11 MUF readings Graph Last 30 days Black Only No Transparent | https://www.hamqsl.com/marston.php |
No Band Condition Calculations Horizontal Selectable 304A Current World Sunlight Map Solar Flux Sunspot No. 11 MUF readings Black Only No Transparent | https://www.hamqsl.com/solarmuf.php |
No Band Condition Calculations Selectable 304A Current World Sunlight Map No Color No Transparent | https://www.hamqsl.com/solarmap.php |
No Band Condition Calculations Selectable 304A Current World Sunlight Globe No Color No Transparent | https://www.hamqsl.com/solarglobe.php |
No Band Condition Calculations Selectable 304A Current World Moon View of Globe EME Deg No Color No Transparent | https://www.hamqsl.com/moonglobe.php |
No Band Condition Calculations Selectable Image Selectable 304A Current Solar System View No Color No Transparent | https://www.hamqsl.com/solarsystem.php |
第二种:来自MUF(3000km) (kc2g.com)
在这个网站上,提供了MUF,foF2(临界频率),eSSN等数据,很方便HAM们获得当日的预测情况
你可以从上面两种方法中任选一种来作为你的Bot将要获取的图像的链接
二、创建Bot
这一步将会十分简单,我会快速略过
首先登录你的Telegram账号并搜索@BotFather,然后输入”/newbot”来创建你的新的Bot,注意,在给你的Bot起Username的时候必须要以”bot”结尾,如”@IzumiChino_bot”
在创建完毕过后,BotFather会给你发送你的Bot的HTTP API,这个API就是你使用你的Bot的凭证,切记切记,不可外传,不可丢失!
准备好了吗,我们要开始写代码了
三、构建Bot代码
在我们一起就绪之后,那离我们的自动化Bot只差一步之遥——写程序,这样就可以让他开始为你服务,发送我们的每日传输预报
为了简单启事,我选用了Python来构建Bot的代码,原因就是Python的库用起来十分方便
构建Bot的代码我们将会用到三个库,分别是 “request”,”bs4″和”python-telegram-bot”
快速地,我们用pip install指令装好这几个需要的库
pip install request
pip install bs4
pip install python-telegram-bot==13.3
你会发现我再安装python-telegram-bot这个库的时候我指定13.3这个版本来安装,具体原因我会在后面说到。
当这些都已经准备好了的时候,你可以新建一个py文件来写代码了
一成不变的,我们先要导入所需要的库
import requests
from datetime import datetime, time, timedelta
from telegram import Bot
from telegram.ext import Updater, CommandHandler
from apscheduler.schedulers.background import BackgroundScheduler
from pytz import utc
其中的telegram和telegram.ext都是包含在python-telegram-bot库当中,代表我们需要从这个库的下属的telegram中引入Bot函数,从telegram.ext中引入Updater和CommandHandler函数
然后,我们进行全局变量的定义(相当于C/C++的const)
#这里填写你的Token
TOKEN = 'INPUT_YOUR_TOKEN_HERE'
#这里填写你希望获得的图片地址
URL = 'INPUT_YOUR_URL_HERE'
接下来我们就需要考虑如何去获取到你希望得到的预测图片,原先我们所使用的BeautifulSoup库中会存在返回图片失败的问题,故我们直接使用Request库来对图片进行获取
代码实现如下:
def get_image_url():
response = requests.get(URL)
if response.status_code == 200:
return response.content
return None
在下一个部分我们要考虑图和通过telegram把图片发送给用户
在这里,我们将会用到telegram.ext里面的update来实时获取用户uid
在写这个子函数之前,我们先定义一个bot,然后运用telegram的Bot函数给他定义
bot = Bot(token=TOKEN)
然后,我们就可以通过python-telegram-bot里所给的函数来将图片发送出去,当图片获取失败的时候会通过bot返回”Failed to get the image”给用户,代码实现如下:
def send_image_to_user(update, context):
if cached_image_data:
chat_id = update.effective_chat.id
bot.send_photo(chat_id=chat_id, photo=cached_image_data, filename='image.jpg')
else:
context.bot.send_message(chat_id=update.effective_chat.id, text="Failed to get the image.")
最后的主程序部分,我们要实时获取用户的输入,一旦用户输入了”/start”发送给机器人,机器人就要立即发送图片给用户,这里我们将会用到CommandHandler函数来定义一个机器人函数的操作,也就是“/getocondition”命令代表着让机器人发送传输预报图象给用户,同时我还写了”/start”指令时bot的回复以及”/help“指令将会输出bot的指令列表给用户,代码实现如下:
def start(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text="请通过 /getcondition 指令来获取当日传播预测图")
def helpcommand(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text="Bot commands:\n/getcondition To get the image of condition\n/help To list commands of the bot\nAuthor:Mashiro Chino")
def main():
fetch_image_data() # 预先获取并缓存图片数据
updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher
start_handler = CommandHandler('start', start)
get_condition_handler = CommandHandler('getcondition', send_image_to_user)
help_handler = CommandHandler('help', helpcommand)
dispatcher.add_handler(start_handler)
dispatcher.add_handler(get_condition_handler)
dispatcher.add_handler(help_handler)
scheduler.add_job(fetch_image_data, 'cron', hour=0, minute=0, second=0) # 每天UTC时间00:00运行任务
scheduler.start()
updater.start_polling()
注意这里的Updater函数,我们只传了一个参数TOKEN给他,在旧版本的python-telegram-bot库当中,这个函数只需要提供一个bot的TOKEN便可以使用,但是在最新版本中,这个函数被要求传递多个参数,使得代码实现更加麻烦(以下为新版定义)
classtelegram.ext.Updater(token: str = None, base_url: str = None, workers: int = 4, bot: telegram.bot.Bot = None, private_key: bytes = None, private_key_password: bytes = None, user_sig_handler: Callable = None, request_kwargs: Dict[str, Any] = None, persistence: BasePersistence = None, defaults: Defaults = None, use_context: bool = True, dispatcher: telegram.ext.dispatcher.Dispatcher = None, base_file_url: str = None)
Parameters: | token (str , optional) – The bot’s token given by the @BotFather.base_url ( str , optional) – Base_url for the bot.base_file_url ( str , optional) – Base_file_url for the bot.workers ( int , optional) – Amount of threads in the thread pool for functions decorated with @run_async (ignored if dispatcher argument is used).bot ( telegram.Bot , optional) – A pre-initialized bot instance (ignored if dispatcher argument is used). If a pre-initialized bot is used, it is the user’s responsibility to create it using a Request instance with a large enough connection pool.dispatcher ( telegram.ext.Dispatcher , optional) – A pre-initialized dispatcher instance. If a pre-initialized dispatcher is used, it is the user’s responsibility to create it with proper arguments.private_key ( bytes , optional) – Private key for decryption of telegram passport data.private_key_password ( bytes , optional) – Password for above private key.user_sig_handler ( function , optional) – Takes signum, frame as positional arguments. This will be called when a signal is received, defaults are (SIGINT, SIGTERM, SIGABRT) settable with idle .request_kwargs ( dict , optional) – Keyword args to control the creation of a telegram.utils.request.Request object (ignored if bot or dispatcher argument is used). The request_kwargs are very useful for the advanced users who would like to control the default timeouts and/or control the proxy used for http communication.use_context ( bool , optional) – If set to True uses the context based callback API (ignored if dispatcher argument is used). Defaults to True . New users: set this to True .persistence ( telegram.ext.BasePersistence , optional) – The persistence class to store data that should be persistent over restarts (ignored if dispatcher argument is used).defaults ( telegram.ext.Defaults , optional) – An object containing default values to be used if not set explicitly in the bot methods. |
---|
因此,相对于新版,旧版本的telegram.ext.Updater()函数更加简洁,容易上手,这就是我使用13.3版本的原因(也是我写这个程序卡了一晚上的原因)
在这段程序里,我添加了一个缓存避免在群组或者私聊里多个人同时发送”/getcondition”指令时会造成发送大量GET指令到hamqsl.com从而造成对他人服务器影响,同时也考虑到应该每日更新一次缓存,我添加了以下子程序
SEND_TIME = time(hour=0, minute=0, second=0)
scheduler = BackgroundScheduler(timezone=utc)
last_update_time = None
def fetch_image_data():
global cached_image_data, last_update_time
cached_image_data = get_image_url()
last_update_time = datetime.utcnow()
好了,代码终于写完了,你可以尝试在你的服务器上运行试试啦,恭喜你获得了一个属于你自己的获取当日传播预测的Telegram Bot!
完整代码如下:
import requests
from datetime import datetime, time, timedelta
from telegram import Bot
from telegram.ext import Updater, CommandHandler
from apscheduler.schedulers.background import BackgroundScheduler
from pytz import utc
TOKEN = 'INPUT_YOUR_TOKEN_HERE'
URL = 'INPUT_YOUR_URL_HERE'
SEND_TIME = time(hour=0, minute=0, second=0)
bot = Bot(token=TOKEN)
scheduler = BackgroundScheduler(timezone=utc)
# 缓存的图片数据和最后更新时间
cached_image_data = None
last_update_time = None
def get_image_url():
response = requests.get(URL)
if response.status_code == 200:
return response.content
return None
def fetch_image_data():
global cached_image_data, last_update_time
cached_image_data = get_image_url()
last_update_time = datetime.utcnow()
def send_image_to_user(update, context):
if cached_image_data:
chat_id = update.effective_chat.id
bot.send_photo(chat_id=chat_id, photo=cached_image_data, filename='image.jpg')
else:
context.bot.send_message(chat_id=update.effective_chat.id, text="Failed to get the image.")
def start(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text="请通过 /getcondition 指令来获取当日传播预测图")
def helpcommand(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text="Bot commands:\n/getcondition To get the image of condition\n/help To list commands of the bot\nAuthor:Mashiro Chino")
def main():
fetch_image_data() # 预先获取并缓存图片数据
updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher
start_handler = CommandHandler('start', start)
get_condition_handler = CommandHandler('getcondition', send_image_to_user)
help_handler = CommandHandler('help', helpcommand)
dispatcher.add_handler(start_handler)
dispatcher.add_handler(get_condition_handler)
dispatcher.add_handler(help_handler)
scheduler.add_job(fetch_image_data, 'cron', hour=0, minute=0, second=0) # 每天UTC时间00:00运行任务
scheduler.start()
updater.start_polling()
if __name__ == '__main__':
main()
由于本文写作时间为凌晨四点至五点,本人还未睡觉,故行文匆忙,若有错误之处,还请麻烦各位指出
小花絮:这是本人跑完之后的结果,可以看到是因为timeout(
Traceback (most recent call last):
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connection.py", line 140, in _new_conn
conn = connection.create_connection(
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\util\connection.py", line 83, in create_connection
raise err
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\util\connection.py", line 73, in create_connection
sock.connect(sa)
TimeoutError: timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 614, in urlopen
httplib_response = self._make_request(conn, method, url,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 360, in _make_request
self._validate_conn(conn)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 857, in _validate_conn
super(HTTPSConnectionPool, self)._validate_conn(conn)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 289, in _validate_conn
conn.connect()
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connection.py", line 284, in connect
conn = self._new_conn()
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connection.py", line 144, in _new_conn
raise ConnectTimeoutError(
telegram.vendor.ptb_urllib3.urllib3.exceptions.ConnectTimeoutError: (<telegram.vendor.ptb_urllib3.urllib3.connection.VerifiedHTTPSConnection object at 0x000001B6470FA690>, 'Connection to api.telegram.org timed out. (connect timeout=5.0)')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\utils\request.py", line 252, in _request_wrapper
resp = self._con_pool.request(*args, **kwargs)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\request.py", line 68, in request
return self.request_encode_body(method, url, fields=fields,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\request.py", line 148, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\poolmanager.py", line 244, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 691, in urlopen
return self.urlopen(method, url, body, headers, retries,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 691, in urlopen
return self.urlopen(method, url, body, headers, retries,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 691, in urlopen
return self.urlopen(method, url, body, headers, retries,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\connectionpool.py", line 665, in urlopen
retries = retries.increment(method, url, error=e, _pool=self,
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\vendor\ptb_urllib3\urllib3\util\retry.py", line 376, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
telegram.vendor.ptb_urllib3.urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded with url: /botTOKEN/getMe (Caused by ConnectTimeoutError(<telegram.vendor.ptb_urllib3.urllib3.connection.VerifiedHTTPSConnection object at 0x000001B6470FA690>, 'Connection to api.telegram.org timed out. (connect timeout=5.0)'))
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:/Users/Mashiro Chino/Desktop/Bot.py", line 33, in <module>
main()
File "C:/Users/Mashiro Chino/Desktop/Bot.py", line 30, in main
updater.start_polling()
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\ext\updater.py", line 285, in start_polling
self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\ext\updater.py", line 225, in _init_thread
name=f"Bot:{self.bot.id}:{name}",
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\bot.py", line 330, in id
return self.bot.id
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\bot.py", line 323, in bot
self._bot = self.get_me()
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\bot.py", line 126, in decorator
result = func(*args, **kwargs)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\bot.py", line 407, in get_me
result = self._post('getMe', timeout=timeout, api_kwargs=api_kwargs)
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\bot.py", line 258, in _post
return self.request.post(
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\utils\request.py", line 349, in post
result = self._request_wrapper(
File "C:\Users\Mashiro Chino\AppData\Local\Programs\Python\Python311\Lib\site-packages\telegram\utils\request.py", line 258, in _request_wrapper
raise NetworkError(f'urllib3 HTTPError {error}') from error
telegram.error.NetworkError: urllib3 HTTPError HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded with url: /botTOKEN/getMe (Caused by ConnectTimeoutError(<telegram.vendor.ptb_urllib3.urllib3.connection.VerifiedHTTPSConnection object at 0x000001B6470FA690>, 'Connection to api.telegram.org timed out. (connect timeout=5.0)'))
睡觉去了,73,再会!
致谢:
传播预测图的获取感谢Neo_Chen(BU4AK)提供的数据并为本人讲解其数据作用!
代码部分感谢huige和acolaen帮助本人纠错、修改代码!
机器人很好用!尤其是雌小鬼功能~
贴贴老婆!喵呜喵!