Github APIからIssueとコメントを取得→はてなブログに投稿するPythonスクリプト書いた
こないだから書いてるやつ、とりあえず形になったので晒してみる。 github.com
コード全体像
# coding:utf-8 import os from os.path import join, dirname from dotenv import load_dotenv import requests from requests.auth import HTTPBasicAuth import json import datetime load_dotenv(verbose=True) dotenv_path = join(dirname(__file__), '.env') load_dotenv(dotenv_path) GITHUB_ID = os.environ.get("GITHUB_ID") REPOSITORY_NAME = os.environ.get("REPOSITORY_NAME") HATENA_ID = os.environ.get("HATENA_ID") BLOG_URL = os.environ.get("BLOG_URL") HATENA_PASSWORD = os.environ.get("HATENA_PASSWORD") def fetchGithub(): dt = datetime.datetime.now() + datetime.timedelta(hours=9) issues_url = "https://api.github.com/repos/{}/{}/issues?direction=asc&state=all&since={}T00:00:0Z" issues = issues_url.format(GITHUB_ID, REPOSITORY_NAME, dt.date()) response = requests.get(issues) res = response.json() blog_title = "Issueなし" blog_body = "無為に過ごした1日" if len(res) != 0: blog_title = res[0]['title'] blog_body = "" for r in res: headline = "### " + r['title'] + "\n" blog_body += headline blog_body += r['body'] + "\n\n" number = str(r['number']) comments_url = "https://api.github.com/repos/{}/{}/issues/{}/comments" response = requests.get(comments_url.format(GITHUB_ID, REPOSITORY_NAME, number)) comments = response.json() for c in comments: blog_body += c['body'] + "\n\n" postHatena(blog_title, blog_body) def postHatena(title, body): date = datetime.datetime.now() xml_template = """<?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app"> <title>{}</title> <author><name>virtual-surfer</name></author> <content type="text/x-markdown">{} </content> <updated>{}</updated> <category term="自動投稿" /> <app:control> <app:draft>yes</app:draft> </app:control> </entry> """.format(title, body, date) headers = { "Content-type": "application/xml" } hatena_url = "https://blog.hatena.ne.jp/{}/{}/atom/entry" request = requests.post( hatena_url.format(HATENA_ID, BLOG_URL), timeout=10, headers=headers, data=xml_template.encode("utf-8"), auth=HTTPBasicAuth(HATENA_ID, HATENA_PASSWORD) ) print(request) def main(): fetchGithub() if __name__ == "__main__": main()
APIを叩くために必要な値は.envから読み込んで定数に入れておいた。
Pythonで.envを読み込むために以下のライブラリを使用。 https://pypi.org/project/python-dotenv/
load_dotenv(verbose=True) dotenv_path = join(dirname(__file__), '.env') load_dotenv(dotenv_path) GITHUB_ID = os.environ.get("GITHUB_ID") REPOSITORY_NAME = os.environ.get("REPOSITORY_NAME") HATENA_ID = os.environ.get("HATENA_ID") BLOG_URL = os.environ.get("BLOG_URL") HATENA_PASSWORD = os.environ.get("HATENA_PASSWORD")
- GITHUB_ID: Githubのアカウント名
- REPOSITORY_NAME: Issue等を取ってくる対象のリポジトリ名
- HATENA_ID: はてなID
- BLOG_URL: 投稿先のブログのドメイン
- HATENA_PASSWORD: はてなブログAtomPubのAPIキー
GithubのAPIからリポジトリごとのIssueを取得
https://docs.github.com/en/rest/reference/issues#list-repository-issues 公式ドキュメントを参考に。
dt = datetime.datetime.now() + datetime.timedelta(hours=9) issues_url = "https://api.github.com/repos/{}/{}/issues?direction=asc&state=all&since={}T00:00:0Z" issues = issues_url.format(GITHUB_ID, REPOSITORY_NAME, dt.date()) response = requests.get(issues) res = response.json()
URLのパラメータは、
- direction: Issueの番号のソート順。先に起こしたものから順番に取りたかったのでasc。
- state: Issueの状態(オープンかクローズか)。今回は状態に関係なく取得したかったのでall。
- since: どの日時以降のIssueを持ってくるか。
sinceは「スクリプトを実行した時点より24時間以内のもの」を取ってこれるよう要改良。 Github上の投稿時間とかちゃんと調べられていない。
Issueのコメントを取得
https://docs.github.com/en/rest/reference/issues#list-issue-comments
ひとつでも対象のIssueがあれば、そのIssueのタイトルをブログのタイトルに設定。
### Issueのタイトル コメント コメント
最終的に本文が↑の形になるように、APIからコメントを取得。
if len(res) != 0: blog_title = res[0]['title'] blog_body = "" for r in res: headline = "### " + r['title'] + "\n" blog_body += headline blog_body += r['body'] + "\n\n" number = str(r['number']) comments_url = "https://api.github.com/repos/{}/{}/issues/{}/comments" response = requests.get(comments_url.format(GITHUB_ID, REPOSITORY_NAME, number)) comments = response.json() for c in comments: blog_body += c['body'] + "\n\n"
はてなブログに下書きとして投稿
http://developer.hatena.ne.jp/ja/documents/blog/apis/atom
はてなブログへの投稿はXML文書を送る必要があるとのことだったが、XML形式の文字列を送ってやるだけで全然行けた。
def postHatena(title, body): date = datetime.datetime.now() xml_template = """<?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app"> <title>{}</title> <author><name>virtual-surfer</name></author> <content type="text/x-markdown">{} </content> <updated>{}</updated> <category term="自動投稿" /> <app:control> <app:draft>yes</app:draft> </app:control> </entry> """.format(title, body, date) headers = { "Content-type": "application/xml" } hatena_url = "https://blog.hatena.ne.jp/{}/{}/atom/entry" request = requests.post( hatena_url.format(HATENA_ID, BLOG_URL), timeout=10, headers=headers, data=xml_template.encode("utf-8"), auth=HTTPBasicAuth(HATENA_ID, HATENA_PASSWORD) )
レスポンスが返ってこなかったときのエラー処理とかは追々書いていく。