Github Actionsを活用して自分のブログを報告してみよう!
Github Actionsを活用して自分のブログを報告してみよう!

Github Actionsを活用して自分のブログを報告してみよう!

작성자
ユミンユミン
카테고리
Dev.Log
작성일
2023년 07월 06일
태그
Project
Github
https://github.com/yuminn-k
 
私が運営しているブログポストをREADME.mdにも見えるように投稿したいと思ってこの機能を実装しました。
本機能を実装しながらコードの効率を高め、不必要な手作業を減らすためにGithub Actionを通じて自動化しました。 これにより、毎日ブログポストを自動的に更新することが可能です。
このポストでは私がどのように機能を実装したかを段階的に書いてみたいと思います。
 

ステップ1: ブログ記事のスクレイピング

まず、ブログの記事をスクレイピングしてくるコードを書く必要があります。 このため、PythonのBeautiful Soupとrequestsライブラリを使いました。
requestsライブラリを使ってブログのHTMLコードを取得した後、BeautifulSoupライブラリを使って必要な情報を抽出します。ブログのHTMLコードからtitle, url, date情報を抽出してpost_data辞書に保存します。
作成したコードは下記の通りです。
import requests from bs4 import BeautifulSoup import json import os import random from pathlib import Path def is_absolute(url): return bool(requests.utils.urlparse(url).netloc) def get_random_blog_posts(url, css_selector): output_data = [] try: response = requests.get(url) response.raise_for_status() soup = BeautifulSoup(response.content, "html.parser") articles = soup.select(css_selector) all_links = [] for article in articles: links = article.find_all("a") all_links.extend(links) selected_links = random.sample(all_links, min(3, len(all_links))) for link in selected_links: # Get the title title_element = link.select_one("div.notion-collection-card-body > div:nth-child(1) > span > span > span > span") title = title_element.text.strip() if title_element else "" # Get the summary summary_element = link.select_one("div.notion-collection-card-body > div:nth-child(2)") summary = summary_element.text.strip() if summary_element else "" # Get the date date_element = link.select_one("div.notion-collection-card-body > div:nth-child(3)") if date_element and '202' in date_element.text: index_202 = date_element.text.index('202') date_text= date_element.text[:index_202] href=link["href"] if not is_absolute(href): href=url.rstrip("/") + href.lstrip(".") post_data={ "title":title, "summary":summary, "date":date_text, "url":href, } output_data.append(post_data) except requests.exceptions.RequestException as e: raise RuntimeError(f"Error while scraping {url}: {e}") return output_data def save_output_to_json(sample_output_data, output_file): output_path = Path(output_file) try: with output_path.open("w") as json_file: json.dump(sample_output_data, json_file) print(f"{output_path}에 성공적으로 저장되었습니다.") except Exception as e: print(f"{output_path}에 저장하는 동안 오류가 발생했습니다: {e}") return str(output_path) def main(): url = os.getenv("URL") css_selector = os.getenv("CSS_SELECTOR") output_file = "output.json" output_data = get_random_blog_posts(url, css_selector) sample_output_data = random.sample(output_data, min(len(output_data), 3)) save_output_to_json(sample_output_data, output_file) if __name__ == "__main__": main()
import json from pathlib import Path def format_post(post): title = post["title"] url = post["url"] return f"[{title}]({url}) " def update_readme(posts): template_path = Path("README_template.md") readme_path = Path("README.md") try: template_content = template_path.read_text() formatted_posts = '\n'.join(format_post(post) for post in posts) with readme_path.open("w") as readme_file: readme_file.write(template_content.format(posts=formatted_posts)) print("README.md 업데이트 성공!") except Exception as e: print(f"README.md 업데이트 도중 오류가 발생했습니다 확인하세요: {e}") def main(): output_file = "output.json" with open(output_file) as json_file: data = json.load(json_file) update_readme(data) if __name__ == "__main__": main()
 

ステップ2: READMEの更新

スクレイピングしたデータを持ってREADMEを更新するには、まずREADME.mdファイルのテンプレートを作成する必要があります。 このテンプレートでブログ記事が入る場所を{blog_posts}と表示しておきます。
... <h2>Blog Posts</h2> {blog_posts} ...
そしてPythonスクリプトを使ってこのテンプレートの {blog_posts} 部分をスクレイピングしたブログ記事に置き換えます。このように修正した内容をREADME.mdで保存したら、READMEが更新されたことになります。
 

ステップ3: GitHub Action設定

本ロジックを毎日午前1時15分に動作させます。
  1. Set up Python Setup Git identityでPython環境を設定し、Gitユーザー情報を設定します。
  1. Check out repository, Add another repositoryで現在のリポジトリと他のリポジトリをチェックアウトし、Install dependenciesでPythonパッケージマネージャPipをアップグレードして必要なパッケージをインストールします。
  1. Run the scriptでブログポストをクロールしてREADME.mdを更新します。
  1. 修正したREADME.mdファイルをGitリポジトリに追加してコミットを生成します。
  1. コミットをリモートリポジトリへpushします。
 
ロジックは以下の通りです。
name: Update README on: schedule: - cron: "0 15 * * *" workflow_dispatch: jobs: update_readme: runs-on: ubuntu-latest steps: - name: Set up Python uses: actions/setup-python@v2 with: python-version: "3.x" - name: Setup Git identity run: | git config --global user.name 'yuminnk' git config --global user.email 'gimyumin40@gmail.com' - name: Check out repository uses: actions/checkout@v2 with: fetch-depth: 0 - name: Add another repository run: git clone https://github.com/yuminn-k/yuminn-k.git && cd yuminn-k - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run the script env: URL: "https://yuminnk-devlog.vercel.app" CSS_SELECTOR: "#__next>div:nth-child(2)>div>div.notion-frame>div>main>div.notion-page-content>article>div.notion-collection.notion-block-52c3f72df427430ca4768e53c36a61c6>div:nth-child(2)>div>div" run: | python blog_posts_scraper.py python update_readme.py git add README.md git commit -m "Updated README.md with recent blog posts" git push origin main
 

まとめ

このようにGithub Actionを使ってブログポストを自動的にREADME.mdに表示する機能を実装しました。 この機能を使ってブログ訪問者に最新の投稿を簡単に知らせることができ、README.mdを最新の状態に保つことができます。
 
この機能を実装するにあたり、以下の点を考慮しました。
  • 毎回ブログポストをクロールしてREADME.mdに更新するのは非効率的なので、Github Actionを使って自動化しました。
  • README.mdに表示される投稿は、ランダムに選択されるようにし、訪問者に様々な投稿を表示できるようにしました。
 
さらに改善すべき点は以下の通りです。
  • 毎回ランダムに出力しますが、曜日ごとに特定のタグのポストを出力するなどの追加条件をつけることも検討できます。
  • 現在はテキストでポストを出力していますが、バッジの形でデザインすることも検討できます。

댓글

guest