Medium記事をMarkdownに変換|効率的な記事バックアップツール
Mediumの記事を簡単にMarkdown形式で保存したい方へ。手軽に心血記事をバックアップし、編集や共有がスムーズになる最適な変換ツールを紹介します。
本記事は AI による翻訳をもとに作成されています。表現が不自然な箇所がありましたら、ぜひコメントでお知らせください。
記事一覧
Mediumの投稿をMarkdownに変換する
Medium の大切な記事をバックアップして Markdown 形式に変換する小ツールの作成
[EN] ZMediumToMarkdown
Mediumの投稿をダウンロードしてMarkdown形式に簡単に変換できるプロジェクトを作成しました。
特徴
投稿のダウンロードとMarkdown形式への変換をサポートしています
ログイン不要で任意のユーザーの全投稿をダウンロードし、Markdown形式に変換をサポート
有料コンテンツのダウンロードをサポート
投稿のすべての画像をローカルにダウンロードし、ローカルパスに変換をサポートする
Twitterのツイート内容を引用ブロックとして解析するサポート
有料コンテンツのダウンロードをサポートする
コマンドラインインターフェースをサポートする
Gist のソースコードをMarkdownのコードブロックに変換する
投稿に埋め込まれたYouTubeリンクをプレビュー画像に変換する
MediumからローカルにダウンロードしたMarkdownファイルの最終更新日時を調整する
投稿が既にダウンロードされており、Mediumの最終更新日が変更されていない場合は自動スキップ(自動同期や自動バックアップサービスに便利で、サーバーの帯域幅と実行時間を節約)
Medium向けに高度に最適化されたMarkdown形式
ネイティブMarkdownスタイルレンダーエンジン(最適化アイデアがあればぜひご協力ください!
MarkupStyleRender.rb)jekyll とソーシャルシェア(og: タグ)対応
100% Ruby @ RubyGem
[CH] ZMediumToMarkdown
Mediumの文章リンクやMediumユーザーの全記事を対象に、その内容をクロールしてMarkdown形式に変換し、記事内の画像とともにダウンロードするバックアップツール。
[2022/07/18 更新]: 手取り足取りでMediumから自分のサイトへ無痛移行
特徴機能
ログイン不要、特別な権限不要
単一記事およびユーザーの全記事のダウンロードとMarkdownへの変換をサポート
記事内のすべての画像をダウンロードして対応する画像パスに変換することをサポートしています
記事内に埋め込まれた Gist を深く解析し、対応する言語の Markdown コードブロックに変換します。
Twitter の内容を解析して記事に貼り付けることをサポートしています
記事内に埋め込まれたYouTube動画を解析し、動画のサムネイル画像とリンクをMarkdownに表示します。
ユーザーのすべての記事をダウンロードする際に、記事内に関連記事が埋め込まれているかをスキャンし、あればリンクをローカルのものに置き換えます。
Medium フォーマットのスタイルに特別最適化
ダウンロードした記事の最終更新/作成日時を、Medium記事の公開日時に自動で変更する
自動でダウンロードした記事の最終更新日時を比較し、Mediumの記事の最終更新日時より古い場合は自動でスキップします
(この機能により、自動Sync/Backupツールの構築が容易になり、サーバーの通信量や時間を節約できます)CLI 操作、自動化対応
本プロジェクトおよび本記事は技術研究のみを目的としており、商業目的や違法行為には使用しないでください。万が一、本内容を用いて違法行為が行われた場合、作者は一切関与しません。ここに明言します。
記事の利用および著作権を確認した上で、ダウンロードとバックアップを行ってください。
起源
Mediumを始めて3年目で、65本以上の記事を投稿してきました。すべての記事はMediumプラットフォームで直接執筆しており、他にバックアップはありません。正直なところ、Mediumのプラットフォームに問題が起きたり、何らかの理由でこれまでの努力が消えてしまうのをずっと心配していました。
以前は手動でバックアップしていましたが、とても退屈で時間がかかるため、すべての記事を自動でバックアップ・ダウンロードできるツール、できればMarkdown形式に変換できるものを探していました。
バックアップの必要性
Markdown フォーマット
ユーザーがそのユーザーのすべての Medium 投稿を自動でダウンロードする方法
記事内の画像もダウンロードしてバックアップできます。
Gist を Markdown のコードブロックにパースできること
(私の Medium では大量に gist を埋め込んだソースコードを使っているので、この機能は非常に重要です)
バックアップ方法
Medium 公式
公式にはエクスポート機能が提供されていますが、エクスポート形式は Medium へのインポート専用で、Markdown や共通フォーマットには対応しておらず、Github Gist などの埋め込みコンテンツは処理されません。
Medium が提供する API はほとんどメンテナンスされておらず、投稿作成機能のみを提供しています。
合理的です。なぜなら Medium の公式はユーザーがコンテンツを他のプラットフォームに簡単に移行することを望んでいないからです。
Chrome 拡張機能
いくつかの Chrome 拡張機能を試しましたが(ほとんどが削除されていました)、効果は良くありませんでした。まず、記事を一つずつ手動で開いてバックアップする必要があり、次に解析されたフォーマットに多くの誤りがあり、Gist のソースコードを深く解析できず、記事内のすべての画像もバックアップできませんでした。
medium-to-markdown コマンドライン
ある有名な方が JavaScript で書いたもので、基本的なダウンロードと Markdown 変換は可能ですが、画像のバックアップや Gist のソースコードの深い解析はできません。
ZMediumToMarkdown
完璧な解決策が見つからなかったため、自分でバックアップ変換ツールを作成することに決めました。約3週間の勤務後の時間を使ってRubyで完成させました。
技術的な詳細
ユーザー名を入力して記事リストを取得する方法
UserIDの取得:ユーザーページ(https://medium.com/@# {username}) のソースコードを確認すると、
Usernameに対応するUserIDが見つかります。
ここで注意すべきは、Mediumがカスタムドメインを再び許可したため、30Xリダイレクトの処理を追加する必要があることです。ネットワークリクエストを解析すると、MediumがGraphQLを使ってホームページの投稿リスト情報を取得していることがわかる
QueryをコピーしてUserIDをリクエスト情報に置き換える
1
2
HOST: https://medium.com/_/graphql
METHOD: POST
- レスポンスの取得
一度に取得できるのは10件までで、ページングして取得する必要があります。
記事一覧:
result[0]->userResult->homepagePostsConnection->postsから取得可能ですhomepagePostsFromページング情報:result[0]->userResult->homepagePostsConnection->pagingInfo->nextで取得可能
homepagePostsFromをリクエストに渡すことでページングアクセスができ、nilの場合は次のページがないことを意味します
記事内容をどのように解析するか?
記事のソースコードを確認すると、MediumはApollo Clientを使って構築されていることがわかります。実際のHTMLはJSによってレンダリングされています。そのため、ソースコード内の<script>セクションでwindow.__APOLLO_STATE__フィールドを見つけることができ、内容は記事全体の段落構造になっています。Mediumは記事を一文ずつの段落に分割し、JSエンジンを通じて再びHTMLにレンダリングしています。
私たちがやることも同じで、この JSON を解析し、Type を Markdown のスタイルと照合して、Markdown 形式を組み立てます。
技術的な難点
ここで技術的な難点は、段落の文字スタイルをレンダリングする際に、Mediumが提供する構造が以下のようになっていることです:
code in text, and link, and ZhgChgLi, and bold, and I, only i
意味は code in text, and link in text, and ZhgChgLi, and bold, and I, only i この部分の:
1
2
3
4
- 5文字目から7文字目まではコード(`Text`形式で囲む)としてマークする
- 18文字目から22文字目まではリンク([Text](URL)形式で囲む)としてマークする
- 50文字目から63文字目までは太字(*Text*形式で囲む)としてマークする
- 55文字目から69文字目までは斜体(_Text_形式で囲む)としてマークする
第 5 から 7 および 18 から 22 はこの例では処理が簡単です。なぜなら交差していないからです。しかし、50–63 および 55–69 は交差の問題があり、Markdown では以下のような交差を表現できません:
1
code `in` text, and [ink](http://zhgchg.li) in text, and ZhgChgLi, and **bold,_ and I, **only i_
正しい組み合わせ結果は以下の通りです:
1
code `in` text, and [ink](http://zhgchg.li) in text, and ZhgChgLi, and **bold,_ and I, _**_only i_
50–55 STRONG 55–63 STRONG, EM 63–69 EM
また注意すべき点:
パッケージ形式の文字列の先頭と末尾は区別できる必要があります。Strong はたまたま先頭と末尾が
**ですが、Link は先頭が[で末尾が](URL)になります。Markdown記号と文字列を結合するときは、前後に空白を入れないよう注意してください。そうしないと機能しません。
この部分は長く研究しましたが、現在は既存のパッケージ reverse_markdown を使って解決しています。
特別に元同僚の Nick 、Chun-Hsiu Liu 、James の協力で研究しました。時間があれば後でネイティブ版を書き直します。
成果
ご質問やご意見がございましたら、こちらからご連絡ください 。
Post は ZMediumToMarkdown によって Medium から変換されました。
本記事は Medium にて初公開されました(こちらからオリジナル版を確認)。ZMediumToMarkdown による自動変換・同期技術を使用しています。

