Ink

Contents related to tech, hobby, etc

Qiitaの記事を全部引っ越ししている [WIP]

|

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

その投稿のタイトルです。

これらのキーの値を用いて:

  1. APIからデータを取得

  2. 本文を body から取得

  3. created_attitle からファイル名を構築する

  4. そのファイルに本文を保存する

という処理がしたい。 これを何を用いてやるか...という話なのですが、ここで「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_attitle からファイル名を構築する

現在、ブログ記事のファイル名は <日付>-<タイトル> のケバブケースになっている。 なのでこの形に合うように整形する。

$"<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. ->-&gt; になるなど) ので、これをデコードしてあげます。

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" }

https://qiita.com/saba_can00/items/02ff28a16a0d312a5259