Mediumの記事を自動でGithub Pages(Jekyll)にバックアップする話
個人 Medium 記事のバックアップミラーサイト構築、運用、アップグレード、カスタマイズに関する記録
はじめに
Mediumの運営は6年目に入り、記事数は昨年100本を突破しました。運営期間が長くなり記事が増えるにつれて、いつかMediumが突然閉鎖されたり、アカウントに異常が起きて全ての記事が消えてしまうのではないかと不安になります。内容の薄い記事もありますが、多くは技術構成や当時の問題解決の思考を記録したもので、私はよく過去の記事を見返して知識を復習しています。また、ここ数年は海外旅行の記録も始めており、これらは思い出でありアクセスも良好です。これらの内容が失われると二度と書き直せません。
自作のバックアップツール開発
私は普段 Medium プラットフォーム上で直接記事を書いており、自分のバックアップを持っていませんでした。そこで2022年の旧正月期間中に、Mediumの記事をダウンロードして Markdown ファイル(記事の画像や埋め込みコードなどを含む)に変換するツール — ZMediumToMarkdown : を開発しました。
そして、このツールでダウンロードした Markdown を Jekyll (Chirpy Theme) を使って静的バックアップミラーサイトとして Github Pages にデプロイしました — https://zhgchg.li/

その時、この一連の流れを同じニーズを持つ友人がすぐに使えるように、Githubのテンプレートリポジトリとしてまとめました — ZMediumToJekyll。その後(2022年以降)、Jekyll (Chirpy Theme) のバージョンや設定は更新していませんが、ZMediumToMarkdown は継続的にメンテナンスしており、時々フォーマット解析の誤りを見つけるとすぐに修正しています。現在は安定してきています。
当時使用していた Jekyll (Chirpy Theme) のバージョンは v5.x で、大きな問題はなく、必要な機能も揃っていました(例:固定表示、カテゴリー、タグ、カバー画像、コメントなど)。ただ、画面のスクロール時にスクロールできなくなることが頻繁にありましたが、数回スクロールすると正常に戻るという操作体験の欠点がありました。v6.x にアップグレードを試みましたが問題は解決せず、公式に報告しても返信がありませんでした。さらにバージョンアップに伴う競合も増えたため、最終的にアップグレードを完全に諦めました。
最近、Jekyll (Chirpy Theme) の問題を解決し、バージョンアップを行い、ついでに高速デプロイツール ZMediumToJekyll を再最適化することを決心しました。
新着!medium-to-jekyll-starter 🎉🎉
medium-to-jekyll-starter.github.io
私は Jekyll (Chirpy Theme) の最新版 v7.x に、自作の ZMediumToMarkdown Medium記事ダウンロード変換ツールを組み合わせて、新しい medium-to-jekyll-starter.github.io Githubテンプレートリポジトリとして再構成しました。
皆さんはこのテンプレートリポジトリを使って、自分の Medium ミラーコンテンツバックアップサイトを素早く設定・構築できます。一度設定すれば永久に自動バックアップが続き、Github Pages 上で完全無料で公開可能です。
手順を追った設定ガイドはこちらの記事をご参照ください: https://zhgchg.li/posts/medium-to-jekyll/
成果

上記のすべての記事は、私の Medium から自動的に*すべての内容をダウンロードし、Markdown 形式に変換して再アップロードしたものです。
適当な記事の変換結果を比較例として添付:
アップグレード後、スクロールが止まる問題は再発しませんでした。今回のアップグレードで、カスタマイズした動的コンテンツ(Mediumのフォロワー数表示)も追加しました。
一部の技術記録
Jekyll (Chirpy Theme) を Github Pages にデプロイする設定方法は、主に公式の Start Repo を直接参照します:
先月もこのプロジェクトの方法を参考にして、新しいオープンソースプロジェクト — Linkyee オープンソース版の Link Tree 個人リンクページを作成しました。

Jekyll カスタマイズ方法 (1) — HTMLのオーバーライド
Jekyll は非常に強力な Ruby 製の静的サイトジェネレーターです。 Jekyll (Chirpy Theme) は Jekyll をベースにしたテーマの一つで、他のテーマと比較しても Chirpy Theme が最も質感が高く、操作体験が優れており、機能も充実しています。
Jekyll のページは継承性があり、./_layouts に Jekyll と同じページファイル名 を追加すると、サイト生成時にエンジンがあなたのカスタムページ内容で元の内容を置き換えます。
例えば、各記事ページの末尾に一行のテキストを追加したい場合、元の投稿ページファイル(post.html)をコピーして、./_layouts ディレクトリに配置します:
![]()
エディタで post.html を開き、該当箇所にテキストやカスタマイズを追加し、サイトを再デプロイするとカスタマイズ結果が反映されます。

./_include ディレクトリを作成して、共有したいページの内容ファイルを入れることもできます:

そして post.html の中で、直接 {% include buymeacoffee.html %} を使って先ほどのファイルの HTML 内容を再利用できます。
HTML Layout ファイルを上書きする利点は、100% カスタマイズ可能で、ページの内容やレイアウトを自由に調整できることです。欠点は、今回のアップグレード時に競合や予期しない結果が発生しやすく、カスタマイズ内容を再確認する必要があることです。
Jekyll カスタマイズ方法 (2) — プラグイン
第二の方法は、Plugin の中の Hook を使い、Jekyll が静的コンテンツを生成する段階で自分のカスタマイズした内容を注入する方法です。


[Builtin Hookの所有者とイベント
Hook イベント](https://jekyllrb.com/docs/plugins/hooks/#built-in-hook-owners-and-events){:target=”_blank”} はたくさんありますが、ここでは私が使った site:pre_render と post:pre_render だけを載せます。
追加方法も非常に簡単で、./_plugins に Ruby ファイルを追加するだけです。

posts-lastmod-hook.rb は元々あるプラグインです
いくつかの「疑似」動的コンテンツ機能が欲しいです。まず一つ目は、プロフィールの下に Medium のフォロワー数を表示し、ページのフッターにページ内容の最終更新日時を表示することです。

./_plugins フォルダに zhgchgli-customize.rb を作成しました:
#!/usr/bin/env ruby
#
require 'net/http'
require 'nokogiri'
require 'uri'
require 'date'
def load_medium_followers(url, limit = 10)
return 0 if limit.zero?
uri = URI(url)
response = Net::HTTP.get_response(uri)
case response
when Net::HTTPSuccess then
document = Nokogiri::HTML(response.body)
follower_count_element = document.at('span.pw-follower-count > a')
follower_count = follower_count_element&.text&.split(' ')&.first
return follower_count \\|\\| 0
when Net::HTTPRedirection then
location = response['location']
return load_medium_followers(location, limit - 1)
else
return 0
end
end
$medium_url = "https://medium.com/@zhgchgli"
# _config.ymlで定義して、Jekyll::Hooks.register :site, :pre_render do \\|site\\| site.configで取得することも可能です
$medium_followers = load_medium_followers($medium_url)
$medium_followers = 1000 if $medium_followers == 0
$medium_followers = $medium_followers.to_s.reverse.scan(/\d{1,3}/).join(',').reverse
Jekyll::Hooks.register :site, :pre_render do \\|site\\|
tagline = site.config['tagline']
followMe = <<-HTML
<a href="#{$medium_url}" target="_blank" style="display: block;text-align: center;font-style: normal;/* text-decoration: underline; */font-size: 1.2em;color: var(--heading-color);">#{$medium_followers}+ Followers on Medium</a>
HTML
site.config['tagline'] = "#{followMe}";
site.config['tagline'] += tagline;
meta_data = site.data.dig('locales', 'en', 'meta');
# 英語のみの実装ですが、他の言語にも実装可能です。
if meta_data
gmt_plus_8 = Time.now.getlocal("+08:00")
formatted_time = gmt_plus_8.strftime("%Y-%m-%d %H:%M:%S")
site.data['locales']['en']['meta'] += "<br/>Last updated: #{formatted_time} +08:00"
end
end
-
原理は、サイトのレンダー前にフックを登録し、config の
tagline個人プロフィール下の紹介内容ブロックに Medium フォロワー数を表示する HTML を追加することです。 -
Medium のフォロワー数は、毎回実行するたびに最新の数字を取得します。
-
ページ下部の最終更新日時のロジックもほぼ同じで、サイト生成時に locales->en->meta に最終更新日時の文字列を追加しています。
-
補足として、Hook が記事生成前の場合は Markdown を取得でき、Hook が記事生成後の場合は生成後の HTML を取得できます。
保存後、まずローカルで bundle exec jekyll s を実行して結果をテストできます:

ブラウザで 127.0.0.1:4000 を開いて結果を確認します。

最後に Github Pages リポジトリの Actions にスケジュールを追加して定期的にサイトを自動再生成するように設定し、完了しました:

在 Jekyll (Chirpy Theme) リポジトリの Actions で「 pages-deploy.yml 」を見つけ、on: に以下を追加します:
schedule:
- cron: "10 1 * * *" # 毎日 UTC 01:10 に自動実行, https://crontab.guru
Plugin の利点は、動的なコンテンツ効果(スケジュール更新)が可能で、サイト構造に影響を与えず、アップグレード時の衝突が起きにくいことです。欠点は、調整できる内容や表示位置に制限があることです。
Jekyll (Chirpy Theme) v7.x 以降の Github Pages デプロイの問題
サイト構成の調整に加え、v.7.x のデプロイスクリプトも変更されました。従来の deploy.sh スクリプトは廃止され、直接 Github Actions のデプロイ手順を使用しています:
# build:
# ...
- name: サイト成果物をアップロード
uses: actions/upload-pages-artifact@v3
with:
path: "_site${{ steps.pages.outputs.base_path }}"
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: GitHub Pagesへデプロイ
id: deployment
uses: actions/deploy-pages@v4
しかし、デプロイの過程で問題が発生しました:
Uploaded artifact size of 1737778940 bytes exceeds the allowed size of 1 GB 私のサイトの内容が大きすぎて、Upload Artifact に失敗しました。しかし、以前のデプロイスクリプトは問題なかったので、元の deploy.sh と 上の部分をコメントアウト する方法に戻しました。
Github Pages デプロイ時に Test Site ステップがいつも通らない
Jekyll (Chirpy Theme) のデプロイには、サイトの内容が正しいかどうかをテストするステップがあります。例えば、リンクが正常か、HTMLタグに欠落がないかなどを検証します。
# build:
# ...
- name: サイトのテスト
run: \\|
bundle exec htmlproofer _site \
\-\-disable-external \
\-\-no-enforce-https \
\-\-ignore-empty-alt \
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
私は自分で --no-enforce-https と --ignore-empty-alt を追加し、https と alt 属性のない HTML タグのチェックを無視しました。これら二つを無視して検査を通過させています(内容をすぐに変更できないため)。
htmlproofer の CLI コマンドは公式ドキュメントに記載がなく、かなり探した結果、ある Issue の Comment でルールを見つけました:

https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268
その他の記事補足
Post は ZMediumToMarkdown によって Medium から変換されました。



コメント