はてなブログからGatsby.jsで作った静的サイトへの記事の移行
ブログを独自ドメインで運用したかったのと,自分の資産として管理したかったので, はてなブログからGatsby.js + Netlifyで作る静的サイトへお引越ししました. (資産というほどの記事は書いていないですが・・・.)
その際,はてなブログからはMovableType形式(html)でしかエクスポートできないようだったので, gatsby-transformer-remark用のMarkdownに変換してディレクトリに格納するスクリプトを書いて移行しました.
ディレクトリ構成
移行後のGatsbyのディレクトリ構成はこんな感じです.
content/blog
├── 2017
│ ├── 03
│ │ └── 02
│ │ └── hello-blog
│ │ └── index.md
│ ├── 10
│ │ ├── 21
│ │ │ └── ios-reject-conf2017-day2
│ │ │ └── index.md
記事ファイル
移行後の記事ファイルはこんな感じです.
content/blog/2017/10/21/ios-reject-conf2017-day2/index.md
---
title: iOSDC 2017 Reject Conference day2 に参加しました
date: 2017-10-21 13:41:26
tags:
- iOS
- Apple
- Swift
- iOSDC
---
今年のiOSDC2017に初めて参加してとても勉強になったので,ぜひReject
Conferenceも参加しようと思ってたんですが,気づいたらすでにday1は終わっており・・・.
スクリプト
ワンタイムで実行する自分用のスクリプトなので,そのままは使えないかもしれませんが,参考まで.
やっていること
- 記事ごとのファイル分割
- タイトル,日時,タグ(カテゴリ)の取得と,frontmatter(gatsby-transformer-remarkが処理する記事のメタデータ)へのセット
- ステータスがPublishの記事をベースネームに相当するディレクトリへ出力
- pandocでhtmlをMarkdownに変換
- はてなブックマーク用のリンク削除
やっていないこと
- 抜粋文の移行
- 途中で改行されているはてなブックマーク用のリンク削除
はてなブログで[App Store](http://d.hatena.ne.jp/keyword/App%20Store)
のように空白を含むリンクを書いていた箇所について,App
とStore
の間に改行が含まれたhtmlで出力されてしまうようでした.
sedで変換が難しかったので,変換結果の確認がてら,変換後のMarkdownを手直ししていきましたが,記事数が多いと大変だと思うので,その場合はスクリプトで改行対応したほうが良いと思います.
実行環境
- Mac: 10.14
- pandoc: 2.4
- はてなブログをエクスポートした日: 2019年9月25日
実行方法
$ ./migration.sh ottijp.hatenablog.com.export.txt output
はてなブログからエクスポートしたファイルと,変換結果の出力先を引数に渡します.
スクリプト
こんな感じです. ファイルの分割処理は自前でやってしまいましたが,csplitコマンドとか使えばよかったかもしれません.
migration.sh
#!/bin/bash
output_dir=$2
init() {
title=
date=
basename=
status=
tags=()
body=()
excerpt=()
inBody=false
inExceprt=false
inComment=false
}
parseHeader() {
# タイトルの特定
temp=$(echo "$1" | grep "^TITLE: " | sed 's/TITLE: \(.*\)/\1/')
if [ -n "$temp" ]; then
title=$temp
return
fi
# 日時の特定
temp=$(echo "$1" | grep "^DATE: " | sed 's/DATE: \(.*\)/\1/')
if [ -n "$temp" ]; then
# YYYY-MM-DD HH:mm:ss形式に変換
date=`echo $temp | sed -E 's|([0-9]{2})/([0-9]{2})/([0-9]{4})(.*)|\3-\1-\2\4|'`
return
fi
# ベースネームの特定
temp=$(echo "$1" | grep "^BASENAME: " | sed 's/BASENAME: \(.*\)/\1/')
if [ -n "$temp" ]; then
basename="$temp"
return
fi
# ステータス
temp=$(echo "$1" | grep "^STATUS: " | sed 's/STATUS: \(.*\)/\1/')
if [ -n "$temp" ]; then
status="$temp"
return
fi
# タグ(カテゴリ)
temp=$(echo "$1" | grep "^CATEGORY: " | sed 's/CATEGORY: \(.*\)/\1/')
if [ -n "$temp" ]; then
tags+=("$temp")
return
fi
}
exportFile() {
[ $status != 'Publish' ] && return
local dirpath="$output_dir/$basename"
local fpath="$dirpath/index.md"
mkdir -p "$dirpath"
# frontmatterヘッダを出力
cat <<-EOS > "$fpath"
---
title: $title
date: $date
tags:
`for e in ${tags[@]}; do echo " - ${e}"; let i++; done`
---
EOS
# markdownに変換し,はてなキーワードのリンクを消して出力
i=0
for e in ${body[@]}; do
echo "${e}"
let i++
done | pandoc -f html -t gfm | sed -E 's|<a href="https?://d.hatena.ne.jp/keyword/[^>]+>([^<]+)<\/a>|\1|g' | sed -E 's|\[([^]]*)\]\(https?://d.hatena.ne.jp/keyword/[^)]*\)|\1|g' >> "$fpath"
}
init
cat $1 | while read line
do
if $inBody; then
if [ "$line" = "-----" ]; then
inBody=false
else
# body出力
body+=($line)
fi
elif $inExceprt; then
if [ "$line" = "-----" ]; then
inExceprt=false
else
# exceprt出力
excerpt+=($line)
fi
elif $inComment; then
if [ "$line" = "-----" ]; then
inComment=false
fi
else
if [ "$line" = "--------" ]; then
# 1つの記事が終了
echo title: $title
echo date: $date
echo basename: $basename
echo status: $status
echo tags: `echo "${tags[@]}" | tr ' ' ','`
echo 本文: ${#body[@]} 行
echo 抜粋: ${#excerpt[@]} 行
echo -----------------------------
exportFile
init
elif [ "$line" = "BODY:" ]; then
# 本文の開始
inBody=true
elif [ "$line" = "EXCERPT:" ]; then
# excerptの開始
inExceprt=true
elif [ "$line" = "COMMENT:" ]; then
# commentの開始
inComment=true
else
# ヘッダのパージング
parseHeader "$line"
fi
fi
done