Qiitaの記事を全部引っ越ししている [WIP]
長らくの間私は Qiitaに記事を書いていましたが、今や自分のページを持つに 至りました。
依然技術系の記事は別に出しても良いのですが、とりあえず このブログには全ての記事を載せておきたかったのでQiitaの記事を引っ越して こようと思います。
行いたいこと
Qiitaにある全ての記事を、ほぼそのまま持ってくる
メタ情報(投稿日時やタグなど)はできるだけ保持する
(管理上の都合で)org文書にコンバートする
画像データもローカルに保存しなおす
注意すること
URIエンコードされているものはデコードする
使うもの
- Qiita API v2
あたり前だがQiitaのAPI。「特定のユーザーの公開記事」なら認証なしで引っ張ってこれる
- nushell
Rust製の、データの扱いに長けたシェル。JSONを素で扱えて楽なので使用する。
- node.js
いわずもがな。Qiita APIが、コンテンツをURIエンコードして返してくるのでデコードするのに使う
作業
TODO 1. Qiitaから情報を取得する
まずはQiitaから情報を引っ張ってきます。
これは /users/:user_id/items
エンドポイントを使用します。
curl https://qiita.com/api/v2/users/Cj-bc/items
これで、指定したユーザーの投稿のリストが取得できます。 各投稿はディクショナリで、そのキーの完全なリストはQiita APIドキュメントの「投稿」に記載されています。
ここでは、今回使うものとして以下のキーを紹介します:
body
Markdown形式で 表現された本文を保持します。 これは URLエンコードされています 。
created_at
この投稿が作成された日時です。ISO8601形式で秒数まで記載されています。
title
その投稿のタイトルです。
これらのキーの値を用いて:
APIからデータを取得
created_at
とtitle
からファイル名を構築するそのファイルに本文を保存する
という処理がしたい。 これを何を用いてやるか...という話なのですが、ここで「JSONデータを扱いやすい」という理由でnushellが出てきます。
最初はjqとか使おうとしてたけど、
そもそもjqはあまり知らない
ファイル名を構築してそこへのリダイレクトが出来なさそう(少なくとも知らない)
文字列に他の処理をかけたい場合がある
というのでjqではなくnushellにしました。
1. APIからデータを取得
nushellでは、ビルトインの fetch
コマンドで HTTPの GET
リクエストを送信できます。
fetch https://qiita.com/api/v2/users/Cj-bc/items
こうすると、JSONをnushellのtableに変換して返してくれます。
2. 本文を body
から取得
このAPIは、「投稿のリスト」を返してくるので、それぞれに対してbodyを取得してあげる。
each
標準入力にリストを取り、その各要素に対してコードブロックを適用します
{}
コードブロックです。この中の
$it
は、このコードブロックに渡されるパラメーターを示します。{|x| }
コードブロックは名前付きでも定義することができます。この場合、
$it
の変わりに$x
を同じ意味で使用できます。(ついでの解説)
fetch https://qiita.com/api/v2/users/Cj-bc/items | each {$it.body}
TODO 3. created_at
と title
からファイル名を構築する
現在、ブログ記事のファイル名は <日付>-<タイトル>
のケバブケースになっている。
なのでこの形に合うように整形する。
$"<text>"
$
から始まる文字列は、文字列埋め込みです。()
で囲んであげた部分を式として評価し、文字列に埋め込みます。str substring <range>
指定の範囲のスライスを作成します。
str kebab-case
標準入力で来た文字列をケバブケースに変換します。
fetch https://qiita.com/api/v2/users/Cj-bc/items | each {$"($it.created_at | str substring [0,10])-($it.title | str kebab-case).md"}
TODO 2. HTMLエンコードを外す
APIから取得した body
は HTMLエンコードされている(e.g. ->
が ->
になるなど)
ので、これをデコードしてあげます。
HTML エンコード と URI エンコード は(異なります。
多分色々な方法が色々な言語にあると思いますが、
一番最初に思い付いた簡単かつ確実なのはnodeを使うことだったのでそうします。
decodeURI
(参考) 使えばよさそう。
console.log
標準出力に出力するために使用します
fs.readFileSync("/dev/stdin", "utf8")
標準入力から読むために使用します
decodeURI
URIエンコードをデコードする関数です。
node -e 'console.log(encodeURI("https://qiita/てすともーど!!!>"))' | node -e 'console.log(decodeURI(fs.readFileSync("/dev/stdin", "utf8")))'
https://qiita/てすともーど!!!>
TODO 3. ファイルに保存する
save
で標準入力からきたものをファイルに保存できます。
つかったものだけ
fetch https://qiita.com/api/v2/users/Cj-bc/items?per_page=86 | each { $it.body | save $"($it.created_at | str substring [0 10])-($it.title|str kebab-case).md" }