用Python構(gòu)建你自己的RSS提示系統(tǒng)
人生苦短,我用 Python,Python 是非常棒的快速構(gòu)建應(yīng)用程序的編程語(yǔ)言。在這篇文章中我們將學(xué)習(xí)如何使用 Python 去構(gòu)建一個(gè) RSS 提示系統(tǒng),目標(biāo)是使用 Fedora 快樂地學(xué)習(xí) Python。如果你正在尋找一個(gè)完整的 RSS 提示應(yīng)用程序,在 Fedora 中已經(jīng)準(zhǔn)備好了幾個(gè)包。
Fedora 和 Python —— 入門知識(shí)
Python 3.6 在 Fedora 中是默認(rèn)安裝的,它包含了 Python 的很多標(biāo)準(zhǔn)庫(kù)。標(biāo)準(zhǔn)庫(kù)提供了一些可以讓我們的任務(wù)更加簡(jiǎn)單完成的模塊的集合。例如,在我們的案例中,我們將使用 sqlite3 模塊在數(shù)據(jù)庫(kù)中去創(chuàng)建表、添加和讀取數(shù)據(jù)。在這個(gè)案例中,我們?cè)噲D去解決的是這樣的一個(gè)特定問題,在標(biāo)準(zhǔn)庫(kù)中沒有包含,而有可能已經(jīng)有人為我們開發(fā)了這樣一個(gè)模塊。***是使用像大家熟知的 PyPI Python 包索引去搜索一下。在我們的示例中,我們將使用 feedparser 去解析 RSS 源。
因?yàn)?feedparser 并不是標(biāo)準(zhǔn)庫(kù),我們需要將它安裝到我們的系統(tǒng)上。幸運(yùn)的是,在 Fedora 中有這個(gè) RPM 包,因此,我們可以運(yùn)行如下的命令去安裝 feedparser:
$ sudo dnf install python3-feedparser
我們現(xiàn)在已經(jīng)擁有了編寫我們的應(yīng)用程序所需的東西了。
存儲(chǔ)源數(shù)據(jù)
我們需要存儲(chǔ)已經(jīng)發(fā)布的文章的數(shù)據(jù),這樣我們的系統(tǒng)就可以只提示新發(fā)布的文章。我們要保存的數(shù)據(jù)將是用來辨別一篇文章的唯一方法。因此,我們將存儲(chǔ)文章的標(biāo)題和發(fā)布日期。
因此,我們來使用 Python sqlite3 模塊和一個(gè)簡(jiǎn)單的 SQL 語(yǔ)句來創(chuàng)建我們的數(shù)據(jù)庫(kù)。同時(shí)也添加一些后面將要用到的模塊(feedparse,smtplib,和 email)。
創(chuàng)建數(shù)據(jù)庫(kù)
#!/usr/bin/python3
import sqlite3
import smtplib
from email.mime.text import MIMEText
import feedparser
db_connection = sqlite3.connect('/var/tmp/magazine_rss.sqlite')
db = db_connection.cursor()
db.execute(' CREATE TABLE IF NOT EXISTS magazine (title TEXT, date TEXT)')
這幾行代碼創(chuàng)建一個(gè)名為 magazine_rss.sqlite
文件的新 sqlite 數(shù)據(jù)庫(kù),然后在數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)名為 magazine
的新表。這個(gè)表有兩個(gè)列 —— title
和 date
—— 它們能存諸 TEXT 類型的數(shù)據(jù),也就是說每個(gè)列的值都是文本字符。
檢查數(shù)據(jù)庫(kù)中的舊文章
由于我們僅希望增加新的文章到我們的數(shù)據(jù)庫(kù)中,因此我們需要一個(gè)功能去檢查 RSS 源中的文章在數(shù)據(jù)庫(kù)中是否存在。我們將根據(jù)它來判斷是否發(fā)送(有新文章的)郵件提示。Ok,現(xiàn)在我們來寫這個(gè)功能的代碼。
def article_is_not_db(article_title, article_date):
""" Check if a given pair of article title and date
is in the database.
Args:
article_title (str): The title of an article
article_date (str): The publication date of an article
Return:
True if the article is not in the database
False if the article is already present in the database
"""
db.execute("SELECT * from magazine WHERE title=? AND date=?", (article_title, article_date))
if not db.fetchall():
return True
else:
return False
這個(gè)功能的主要部分是一個(gè) SQL 查詢,我們運(yùn)行它去搜索數(shù)據(jù)庫(kù)。我們使用一個(gè) SELECT
命令去定義我們將要在哪個(gè)列上運(yùn)行這個(gè)查詢。我們使用 *
符號(hào)去選取所有列(title
和 date
)。然后,我們使用查詢的 WHERE
條件 article_title
和 article_date
去匹配標(biāo)題和日期列中的值,以檢索出我們需要的內(nèi)容。
***,我們使用一個(gè)簡(jiǎn)單的返回 True
或者 False
的邏輯來表示是否在數(shù)據(jù)庫(kù)中找到匹配的文章。
在數(shù)據(jù)庫(kù)中添加新文章
現(xiàn)在我們可以寫一些代碼去添加新文章到數(shù)據(jù)庫(kù)中。
def add_article_to_db(article_title, article_date):
""" Add a new article title and date to the database
Args:
article_title (str): The title of an article
article_date (str): The publication date of an article
"""
db.execute("INSERT INTO magazine VALUES (?,?)", (article_title, article_date))
db_connection.commit()
這個(gè)功能很簡(jiǎn)單,我們使用了一個(gè) SQL 查詢?nèi)ゲ迦胍粋€(gè)新行到 magazine
表的 article_title
和 article_date
列中。然后提交它到數(shù)據(jù)庫(kù)中***保存。
這些就是在數(shù)據(jù)庫(kù)中所需要的東西,接下來我們看一下,如何使用 Python 實(shí)現(xiàn)提示系統(tǒng)和發(fā)送電子郵件。
發(fā)送電子郵件提示
我們使用 Python 標(biāo)準(zhǔn)庫(kù)模塊 smtplib 來創(chuàng)建一個(gè)發(fā)送電子郵件的功能。我們也可以使用標(biāo)準(zhǔn)庫(kù)中的 email 模塊去格式化我們的電子郵件信息。
def send_notification(article_title, article_url):
""" Add a new article title and date to the database
Args:
article_title (str): The title of an article
article_url (str): The url to access the article
"""
smtp_server = smtplib.SMTP('smtp.gmail.com', 587)
smtp_server.ehlo()
smtp_server.starttls()
smtp_server.login('your_email@gmail.com', '123your_password')
msg = MIMEText(f'\nHi there is a new Fedora Magazine article : {article_title}. \nYou can read it here {article_url}')
msg['Subject'] = 'New Fedora Magazine Article Available'
msg['From'] = 'your_email@gmail.com'
msg['To'] = 'destination_email@gmail.com'
smtp_server.send_message(msg)
smtp_server.quit()
在這個(gè)示例中,我使用了谷歌郵件系統(tǒng)的 smtp 服務(wù)器去發(fā)送電子郵件,在你自己的代碼中你需要將它更改為你自己的電子郵件服務(wù)提供者的 SMTP 服務(wù)器。這個(gè)功能是個(gè)樣板,大多數(shù)的內(nèi)容要根據(jù)你的 smtp 服務(wù)器的參數(shù)來配置。代碼中的電子郵件地址和憑證也要更改為你自己的。
如果在你的 Gmail 帳戶中使用了雙因子認(rèn)證,那么你需要配置一個(gè)密碼應(yīng)用程序?yàn)槟愕倪@個(gè)應(yīng)用程序提供一個(gè)唯一密碼??梢钥催@個(gè) 幫助頁(yè)面。
讀取 Fedora Magazine 的 RSS 源
我們已經(jīng)有了在數(shù)據(jù)庫(kù)中存儲(chǔ)文章和發(fā)送提示電子郵件的功能,現(xiàn)在來創(chuàng)建一個(gè)解析 Fedora Magazine RSS 源并提取文章數(shù)據(jù)的功能。
def read_article_feed():
""" Get articles from RSS feed """
feed = feedparser.parse('https://fedoramagazine.org/feed/')
for article in feed['entries']:
if article_is_not_db(article['title'], article['published']):
send_notification(article['title'], article['link'])
add_article_to_db(article['title'], article['published'])
if __name__ == '__main__':
read_article_feed()
db_connection.close()
在這里我們將使用 feedparser.parse
功能。這個(gè)功能返回一個(gè)用字典表示的 RSS 源,對(duì)于 feedparser 的完整描述可以參考它的 文檔。
RSS 源解析將返回***的 10 篇文章作為 entries
,然后我們提取以下信息:標(biāo)題、鏈接、文章發(fā)布日期。因此,我們現(xiàn)在可以使用前面定義的檢查文章是否在數(shù)據(jù)庫(kù)中存在的功能,然后,發(fā)送提示電子郵件并將這個(gè)文章添加到數(shù)據(jù)庫(kù)中。
當(dāng)運(yùn)行我們的腳本時(shí),***的 if
語(yǔ)句運(yùn)行我們的 read_article_feed
功能,然后關(guān)閉數(shù)據(jù)庫(kù)連接。
運(yùn)行我們的腳本
給腳本文件賦于正確運(yùn)行權(quán)限。接下來,我們使用 cron 實(shí)用程序去每小時(shí)自動(dòng)運(yùn)行一次我們的腳本。cron 是一個(gè)作業(yè)計(jì)劃程序,我們可以使用它在一個(gè)固定的時(shí)間去運(yùn)行一個(gè)任務(wù)。
$ chmod a+x my_rss_notifier.py
$ sudo cp my_rss_notifier.py /etc/cron.hourly
為了使該教程保持簡(jiǎn)單,我們使用了 cron.hourly
目錄每小時(shí)運(yùn)行一次我們的腳本,如果你想學(xué)習(xí)關(guān)于 cron 的更多知識(shí)以及如何配置 crontab,請(qǐng)閱讀 cron 的 wikipedia 頁(yè)面。
總結(jié)
在本教程中,我們學(xué)習(xí)了如何使用 Python 去創(chuàng)建一個(gè)簡(jiǎn)單的 sqlite 數(shù)據(jù)庫(kù)、解析一個(gè) RSS 源、以及發(fā)送電子郵件。我希望通過這篇文章能夠向你展示,使用 Python 和 Fedora 構(gòu)建你自己的應(yīng)用程序是件多么容易的事。
這個(gè)腳本在 GitHub 上可以找到。