検証の動機
Claude CodeでTechニュースを自動配信させてますが、
仕組み自体を学びたいと感じ、備忘録として残す為。
目的
今回は、
- API構造を理解する
- Docker、Ubuntu、MySQLでDBを扱う
- venvを理解する
- cronによる定期実行を理解する
を目的に学習を行います。
進め方
- 方針やコードはAIを活用しつつ、公式doc、エンジニア記事を確認し理解しながら進める
- ニュースサイトは、イギリス大手のGuardian誌を採用
(TechnologyURLがある為、そのURL内の記事をピックアップ出来る為) - Ubuntu / WSL上でcronによる毎朝7時配信まで行います
- Docker、Ubuntu、Pythonなどは既に使える状況で進めます
実装手順
1. Guardian APIキーを取得する
上記のサイトにて、Developerを選択、登録を進めて、APIキーを取得します。
2. 作業ディレクトリを作成する
まずは作業用ディレクトリを作成します。
mkdir C:\tech-news-pipeline
cd C:\tech-news-pipeline
今回は以下のような構成で進めます。
tech-news-pipeline/
├─ compose.yaml
├─ .env
├─ .gitignore
├─ requirements.txt
├─ fetch_guardian_news.py
└─ logs/
└─ cron.log
3. 必要ファイルを作成する
PowerShellで必要ファイルを作成します。
New-Item compose.yaml
New-Item .env
New-Item .gitignore
New-Item requirements.txt
New-Item fetch_guardian_news.py
mkdir logs
compose.yaml
services:
mysql:
image: mysql:8.0
container_name: tech-mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
fetch_guardian_news.py
#各機能を使用する為のライブラリインポート
import os
import smtplib
from email.message import EmailMessage
import mysql.connector
import requests
from dotenv import load_dotenv
#.envファイルを読み込む
load_dotenv()
api_key = os.getenv("GUARDIAN_API_KEY")
#APIキーがなければエラーを出して処理を止める
if not api_key:
raise ValueError("GUARDIAN_API_KEY が設定されていません。")
#MySQLへ接続する
conn = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
port=int(os.getenv("MYSQL_PORT", "3306")),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE"),
)
#SQLを実行するcursorを作成
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title TEXT,
url TEXT,
summary TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
#Guardian APIの公式検索用URL。ここにHTTP GETリクエストを送る
url = "https://content.guardianapis.com/search"
#Guardian API公式で確認してきた情報を以下のように登録
params = {
"api-key": api_key,
"section": "technology",
"page-size": 5,
"show-fields": "trailText",
"order-by": "newest",
}
#APIキーを渡して、technologyの記事を5件、概要文も取得して新しい記事順で取得するという意味
#Guardian APIへHTTP GETリクエスト、paramsの内容を要求、10秒応答無ければ中止する
response = requests.get(url, params=params, timeout=10)
#API失敗時に例外を出す
response.raise_for_status()
#APIレスポンスをPython形式へ変換する。
data = response.json()
#取得した記事一覧を取り出す
articles = data["response"]["results"]
#メール本文の最初の文字列を作成(\nは改行)
mail_body = "Today's English Tech News\n\n"
#取得した記事を1件ずつ処理する
for article in articles:
title = article["webTitle"]
article_url = article["webUrl"]
summary = article.get("fields", {}).get("trailText", "")
#取得した記事をDBへ保存する
#「%s,」=SQL文が壊れないようにする
cursor.execute(
"""
INSERT INTO articles (title, url, summary)
VALUES (%s, %s, %s)
""",
(title, article_url, summary),
)
mail_body += f"Title: {title}\n"
mail_body += f"URL: {article_url}\n"
mail_body += f"Summary: {summary}\n"
mail_body += "-" * 50 + "\n"
#DBに保存される
conn.commit()
#cursorを閉じる
cursor.close()
#MySQLとの接続を閉じる
conn.close()
#送信元Gmailアドレス、App PW、送信先アドレスを.envから取得する
gmail_address = os.getenv("GMAIL_ADDRESS")
gmail_app_password = os.getenv("GMAIL_APP_PASSWORD")
mail_to = os.getenv("MAIL_TO")
#メールを作成する
message = EmailMessage()
message["Subject"] = "Today's English Tech News"
message["From"] = gmail_address
message["To"] = mail_to
message.set_content(mail_body)
#GmailのSMTPサーバにSSL接続する (with as = 処理が終わったら接続を切る)
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
smtp.login(gmail_address, gmail_app_password)
smtp.send_message(message)
print(f"{len(articles)}件の記事をMySQLに保存し、Gmailに送信しました。")
requirements.txt
requests
python-dotenv
mysql-connector-python
各ライブラリの用途は以下です。
| ライブラリ | 用途 |
|---|---|
| requests | Guardian APIへHTTPリクエストを送る |
| python-dotenv |
.env ファイルを読み込む |
| mysql-connector-python | PythonからMySQLへ接続する |
.env
GUARDIAN_API_KEY=Guardian APIで取得したAPIキー
MYSQL_ROOT_PASSWORD=任意のパスワード
MYSQL_DATABASE=technews
MYSQL_USER=app
MYSQL_PASSWORD=任意のパスワード
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
GMAIL_ADDRESS=自身のGmailアドレス
GMAIL_APP_PASSWORD=(16桁のApp PW)
MAIL_TO=自身のGmailアドレス
.gitignore
.env
.venv/
logs/
__pycache__/
こちらの記事を参考にしました。
Git運用の学習も兼ねて作成しました。
Python環境を準備する
4. Python仮想環境(venv)を作成する
venvについての理解は、こちらの記事を参考にしました
python3 -m venv .venv
上記コマンドを、WSL上の作業フォルダディレクトリで実行します。
source .venv/bin/activate
上記コマンドで仮想環境を有効化します。
その後、bashのプロンプト先頭に (.venv) が表示される
5. ライブラリをインストールする
pip install -r requirements.txt
上記コマンドでrequirements.txtのライブラリを一括インストールします。
pip list
pip listを打つと、インストールされたライブラリが確認できます。
Docker ComposeでMySQLを構築する
6. Docker Composeを起動する
以下コマンドでMySQLコンテナを起動します。
docker compose up -d
コンテナ確認。
docker ps
以下のように tech-mysql が表示されればOKです。
CONTAINER ID IMAGE NAMES
xxxxxxxxxxxx mysql:8.0 tech-mysql
7. MySQLへ接続確認する
以下コマンドでMySQLコンテナへ入ります。
docker exec -it tech-mysql mysql -u app -p
パスワード入力後、以下でDB確認します。
SHOW DATABASES;
technews が表示されればOKです。
Pythonコードを実行する
8. Pythonコードを実行する
.venv/bin/python fetch_guardian_news.py
成功すると実際にメールが届き、以下のように表示されます。
5件の記事をMySQLに保存し、Gmailに送信しました。
9. DBへ保存されたか確認する
MySQLへ接続します。
docker exec -it tech-mysql mysql -u app -p technews
以下SQLを実行します。
SELECT id, title, url, created_at
FROM articles
ORDER BY id DESC
LIMIT 5;
記事タイトル、URL、保存日時が表示されればOKです。
cronで毎朝7時に自動実行する
10. cron設定を行う
Ubuntu / WSL 環境上で cron を使用します。
crontab を編集します。
crontab -e
動作確認のため一時的に以下の毎分コマンドを一番下の行に追加し、Ctrl + O で保存。
* * * * * cd /mnt/c/tech-news-pipeline && /mnt/c/tech-news-pipeline/.venv/bin/python fetch_guardian_news.py >> /mnt/c/tech-news-pipeline/logs/cron.log 2>&1
保存後、Gmailに記事が無事届いたらcronの動作確認が完了です。
改めて、以下の朝7時トリガーのコマンドに編集したら完了です。
0 7 * * * cd /mnt/c/tech-news-pipeline && /mnt/c/tech-news-pipeline/.venv/bin/python fetch_guardian_news.py >> /mnt/c/tech-news-pipeline/logs/cron.log 2>&1
意味としては以下です。
| 記述 | 意味 |
|---|---|
| 0 7 * * * | 毎朝7時実行 |
| cd | プロジェクトディレクトリへ移動 |
| .venv/bin/python | 仮想環境Pythonを使用 |
| >> cron.log | ログを追記 |
| 2>&1 | エラーもログへ出力 |
今後試したいこと
Github Actionsを使用して、完全自動化を実現