天天看點

用Python做一個Telegram的新聞Bot

在這篇文章中,我們建構一個高可用的Telegram機器人,用來在成千上萬的新聞源當中搜尋内容。
用Python做一個Telegram的新聞Bot

介紹

Telegram 現在是一個全球流行的實時消息應用,它的特點是安全性和高效性,除了可以互相發送消息以外,還可以在它上面建立bot用來自動執行一些任務。

在這個教程中,我們将用Python和Telegram’s bot API 建立一個基于Datanews的新聞bot。

Telegram API 簡單介紹

我們将使用官方的

python-telegram-bot

Api,這個庫大大簡化了開發Bot的工作,而且通過一些官方給出的例子,很容易學習和掌握它,下面是一個例子:

from telegram.ext import Updater, CommandHandler


USAGE = '/greet <name> - Greet me!'


def start(update, context):
  update.message.reply_text(USAGE)


def greet_command(update, context):
  update.message.reply_text(f'Hello {context.args[0]}!')


def main():
  updater = Updater("TOKEN", use_context=True)
  dp = updater.dispatcher 

  # on different commands - answer in Telegram 
  dp.add_handler(CommandHandler("start", start)) 
  dp.add_handler(CommandHandler("greet", greet_command)) 

  # Start the Bot 
  updater.start_polling() 
  updater.idle() 


if __name__ == '__main__': 
  main()
           

這個小代碼片段建立了一個bot用來識别兩個指令:

  1. /start

    - Bot會根據這個指令響應出幫助頁面
  2. /greet

    - 這個指令會接受一個參數,例如

    Datanews

    ,然後傳回

    Hello Datanews!

來看看每一行代碼的含義:

main

方法

def main():
  updater = Updater("TOKEN", use_context=True)
  dp = updater.dispatcher

  dp.add_handler(CommandHandler("start", start))
  dp.add_handler(CommandHandler("greet", greet_command))

  updater.start_polling()
  updater.idle()
           

這個方法配置了一些Bot工作必要的參數,特别是

Update

類的執行個體,需要注意的是,你需要一個Telegram的

token

才能使用Telegram Bot 的API,你可以檢視這個建立Bot的官方指南點這裡。

回到代碼,

Updater

的目的是為了将更新傳遞給

Dispatcher

,當後者收到一個更新,它将處理使用者指定的一些回調請求,每一個回調都由一個程式管理。

當收到的消息滿足某些條件時,雖然這些條件取決于程式,也可以由開發者自己定義,就我們而言我們有兩個任務處理執行個體。

dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("greet", greet_command))
           

上面的每一條處理一個指令,用來支援我們Bot的

/start

/greet

然後我們調用

start_polling

指令。

updater.start_polling()

這個指令會讓我們的bot周期性的處理更新,這個參數會在内部建立兩個程序,一個用來從Telegram伺服器輪詢更新,另一個将由排程程式處理這些更新。

下面這一行確定我們的bot可以正确的處理各種中斷信号

updater.idle

現在我們讨論兩個處理bot指令的回調函數:

def start(update, context):
  update.message.reply_text(USAGE)


def greet_command(update, context):
  update.message.reply_text(f'Hello {context.args[0]}!')
           

上面每一個方法都需要兩個參數:

  1. update

    從Telegram伺服器收到一個更新
  2. context

    包含一些有用的參數和資訊,舉個例子,它有一個用來儲存使用者相關資訊的

    user_data

    字典

除此以外,每一個參數都會給使用者傳回一條消息。

Datanews API 介紹

Datanews 是一個用來從成千上萬個新聞源中取回和監控新聞的API,新聞聚合器和其他網站,每天收集并處理了數十萬的新聞資料,當然,它也提供了靈活和簡單可用的API用來檢索這些新聞文章。

對于我們這個小項目,我們隻需要API中的一小部分,特别是我們想讓bot能做什麼:

  1. 根據使用者輸入的關鍵字傳回新聞内容
  2. 根據特定的新聞源傳回新聞内容

這些用例需求可以用一個入口處理-

/headlines

, 你可以在後面連結中了解到更多相關的APIofficial documentation.

程式實施

首先,我們要定義一個處理

/start

指令的回調函數

def get_usage():
  return '''This bot allows you to query news articles from Datanews API.

Available commands:
/help, /start - show this help message.
/search <query> - retrieve news articles containing <query>.
  Example: "/search covid"
/publisher <domain> - retrieve newest articles by publisher.
  Example: "/publisher techcrunch.com"'''

def help_command(update, context):
  update.message.reply_markdown(get_usage())
           

就像你看到的,這個實作方式與我們上面示範的很相似,我們簡單的傳回了一個help資訊給使用者,你可以注意到我們的bot支援四個指令,下面我們讨論其他兩個:

def search_command(update, context):
  def fetcher(query):
    return datanews.headlines(query, size=10, sortBy='date', page=0, language='en')
  _fetch_data(update, context, fetcher)


def publisher_command(update, context):
  def fetcher(query):
    return datanews.headlines(source=query, size=10, sortBy='date', page=0, language='en')
  _fetch_data(update, context, fetcher)
           

這些方法看起來都非常簡單,它們都用了我們前面讨論過的

/headlines

API,唯一的差別是我們傳遞給Datanews API的參數:search_command檢索與特定查詢比對的文章,而Publisher_command提取所有由特定來源釋出的文章,這兩個方法中我們都隻活去10條最近的文章。

def _fetch_data(update, context, fetcher):
  if not context.args:
    help_command(update, context)
    return

  query = '"' + ' '.join(context.args) + '"'
  result = fetcher(query)

  if not result['hits']:
    update.message.reply_text('No news is good news')
    return

  last_message = update.message
  for article in reversed(result['hits']):
    text = article['title'] + ': ' + article['url']
    last_message = last_message.reply_text(text)
           

這個方法簡單的檢查了使用者輸入的特定的參數,從Datanews API中取出資料并排序傳回給使用者,

  1. 我們確定用“包圍查詢”,以便Datanews傳回所有包含完整查詢的文章,而不僅僅是其中的一個單詞。
  2. 我們還要確定處理無法查詢到文章的情況,如果這種情況下bot無反應是扯淡的。
  3. 我們發送給使用者的内容必須確定排序後的内容最後一條是最新的内容。

有了這些功能,我們看一下主程式:

def main():
  updater = Updater(token='TOKEN')

  updater.dispatcher.add_handler(CommandHandler('start', help_command))
  updater.dispatcher.add_handler(CommandHandler('help', help_command))
  updater.dispatcher.add_handler(CommandHandler('search', search_command))
  updater.dispatcher.add_handler(CommandHandler('publisher', publisher_command))

  updater.dispatcher.add_handler(
    MessageHandler(
      Filters.text & Filters.regex(pattern=re.compile('help', re.IGNORECASE)),
      help_command
    )
  )

  updater.start_polling()
  updater.idle()
           

這個程式看起來和前面的例子非常相似,隻有一個主要差別是下面:

updater.dispatcher.add_handler(
  MessageHandler(
    Filters.text & Filters.regex(pattern=re.compile('help', re.IGNORECASE)),
    help_command
  )
)

           

MessageHandler

用來獲得使用者的輸入,你可以認為它是

CommandHandler

的類似功能,它可以處理任何滿足指定過濾器的消息,在我們的六種,我們想在使用者輸入資訊中包含help的時候将幫助資訊傳回給使用者。

是以,我們有了一個完全程式化的新聞機器人。

此文章翻譯自https://datanews.io/blog/building-telegram-news-bot-2020

關注公衆号獲得更多最新的精彩内容。

用Python做一個Telegram的新聞Bot