技術ニュースや公式ブログを追いかけていると、RSSリーダー、GitHubのWatch、検索結果など、情報の入口が少しずつ分散していきます。すべてを確認しようとすると時間がかかり、逆に絞りすぎると重要な更新を見落とします。
そこで今回は、RSSとGitHub APIから情報を取得し、ブラウザで確認できる小さな個人ダッシュボードを作りました。結論から言うと、外部サービスを大きく作り込まなくても、PythonとStreamlitだけで「自分が見るべき技術情報」を一つの画面にまとめられます。
この記事では、RSSフィードの記事一覧と、GitHubリポジトリの最新リリースを取得して表示します。
作成するダッシュボードの構成
ダッシュボードが情報を取得して表示するまでの流れを図にすると次の通りです。
今回の構成は次のとおりです。
- RSSから技術ブログやニュースの記事を取得
- GitHub APIから指定リポジトリの最新リリースを取得
- キーワードで記事を簡易フィルタリング
- Streamlitでブラウザ表示
- GitHub APIのトークンは環境変数から読み込む
RSSはニュースやブログの更新確認に向いています。一方、GitHub APIはリポジトリのリリースや更新情報を構造化されたデータとして取得できます。
まず、作業用ディレクトリを作り、必要なライブラリをインストールします。
mkdir tech-dashboard
cd tech-dashboard
python -m venv .venv
.venv\Scripts\activate
pip install streamlit feedparser requests python-dotenv
macOSやLinuxの場合は、仮想環境の有効化コマンドが異なります。
source .venv/bin/activate
RSSフィードを取得する
RSSの取得には feedparser を使います。フィードごとにXMLの項目名が少し異なりますが、タイトル、URL、公開日時は多くのフィードで利用できます。
まずは、RSSを取得する関数を作ります。
# dashboard.py
from datetime import datetime
from email.utils import parsedate_to_datetime
import feedparser
RSS_FEEDS = {
"Python Blog": "https://blog.python.org/feeds/posts/default",
"Real Python": "https://realpython.com/atom.xml",
}
def parse_date(entry):
value = entry.get("published") or entry.get("updated")
if not value:
return ""
try:
return parsedate_to_datetime(value).strftime("%Y-%m-%d")
except (TypeError, ValueError):
return value[:10]
def fetch_rss_items():
items = []
for source, url in RSS_FEEDS.items():
feed = feedparser.parse(url)
for entry in feed.entries[:20]:
items.append(
{
"source": source,
"title": entry.get("title", "タイトルなし"),
"url": entry.get("link", ""),
"date": parse_date(entry),
}
)
return sorted(items, key=lambda item: item["date"], reverse=True)
実際に試すと、RSSによって日付の形式やフィールド名が異なることがありました。そのため、published がない場合は updated を参照し、日付を取得できない場合もエラーにしないようにしています。
フィードのURLは、対象サイトが公開している正式なRSSを指定します。サイトのHTMLページを無理に解析するより、RSSを利用したほうが構造変更の影響を受けにくくなります。
GitHub APIからリリースを取得する
次に、GitHub APIから指定リポジトリのリリースを取得します。今回は、リポジトリ名を owner/repository 形式で指定します。
import os
import requests
from dotenv import load_dotenv
load_dotenv()
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
GITHUB_REPOS = [
"python/cpython",
"pallets/flask",
]
def fetch_github_releases():
headers = {
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
}
if GITHUB_TOKEN:
headers["Authorization"] = f"Bearer {GITHUB_TOKEN}"
releases = []
for repo in GITHUB_REPOS:
response = requests.get(
f"https://api.github.com/repos/{repo}/releases",
headers=headers,
params={"per_page": 5},
timeout=10,
)
response.raise_for_status()
for release in response.json():
releases.append(
{
"repository": repo,
"name": release.get("name") or release.get("tag_name"),
"url": release.get("html_url"),
"date": release.get("published_at", "")[:10],
}
)
return sorted(releases, key=lambda item: item["date"], reverse=True)
公開リポジトリの情報を見るだけなら、トークンなしでも動作します。ただし、APIにはレート制限があるため、継続的に使う場合はGitHubのPersonal Access Tokenを用意しておくほうが安定します。
プロジェクト直下に .env を作り、トークンを保存します。
GITHUB_TOKEN=ここにGitHubのトークンを設定
.env はGitにコミットしないよう、.gitignore に追加します。
.venv/
.env
__pycache__/
トークンには、今回の用途で不要な権限を付けないことも重要です。公開情報の取得だけであれば、リポジトリを書き換える権限は必要ありません。
Streamlitで画面を作る
取得したデータを画面に表示します。検索キーワードを指定すると、RSS記事のタイトルと概要を絞り込めるようにしました。
import streamlit as st
st.set_page_config(
page_title="Tech News Dashboard",
page_icon="📰",
layout="wide",
)
st.title("📰 Tech News Dashboard")
st.caption("RSSとGitHub APIから取得した技術情報")
keyword = st.text_input(
"RSS記事をキーワードで絞り込む",
placeholder="例: Python",
)
if st.button("情報を更新"):
st.cache_data.clear()
rss_items = fetch_rss_items()
github_releases = fetch_github_releases()
if keyword:
rss_items = [
item for item in rss_items
if keyword.lower() in item["title"].lower()
]
st.subheader("RSSニュース")
if not rss_items:
st.info("条件に一致する記事はありません。")
else:
for item in rss_items:
st.markdown(
f"- **{item['date']} [{item['source']}]** "
f"[{item['title']}]({item['url']})"
)
st.subheader("GitHub Releases")
for release in github_releases:
st.markdown(
f"- **{release['date']} [{release['repository']}]** "
f"[{release['name']}]({release['url']})"
)
アプリを起動します。
streamlit run dashboard.py
ブラウザで表示されたURLを開くと、RSS記事とGitHubのリリース一覧を確認できます。フィードの取得に失敗した場合は、URLの誤りだけでなく、サイト側の一時的な障害やSSL証明書の問題も考えられます。まずはブラウザや curl でRSS URLが開けるか確認すると切り分けやすくなります。
キャッシュと運用上の注意
画面を更新するたびにRSSやGitHub APIへアクセスすると、不要なリクエストが増えます。そこで、取得結果を一定時間キャッシュします。
@st.cache_data(ttl=900)
def cached_rss_items():
return fetch_rss_items()
@st.cache_data(ttl=900)
def cached_github_releases():
return fetch_github_releases()
画面側では、次のように呼び出します。
rss_items = cached_rss_items()
github_releases = cached_github_releases()
ttl=900 は15分間キャッシュする設定です。個人利用であれば、数分単位で最新情報に更新されなくても困らないケースが多いため、適度なキャッシュを入れておくと扱いやすくなります。
また、RSSの内容をそのままHTMLとして表示する処理には注意が必要です。今回はタイトルとURLだけを表示し、取得したHTML本文は表示しない構成にしました。外部データを画面に埋め込むときは、不要なHTMLやスクリプトをそのまま描画しないことが大切です。
まとめ
RSSとGitHub APIを組み合わせると、普段見ている技術情報を自分向けの画面にまとめられます。今回の実装では、次のことを確認しました。
-
feedparserで複数のRSSをまとめて取得できる - GitHub APIで指定リポジトリのリリースを取得できる
- Streamlitを使うと少ないコードでダッシュボード化できる
- APIトークンは環境変数で管理する
- キャッシュを使うことで不要なアクセスを減らせる
次に拡張するなら、既読管理、タグごとの分類、GitHubのIssueやPull Requestの表示、SQLiteへの保存などが考えられます。
最初から高機能なニュースサービスを作るのではなく、「毎日確認したい情報」を少しずつ追加していくと、自分の作業スタイルに合ったダッシュボードに育てやすいと感じました。