Closed6

しずかなインターネットをobsidianにいれる

ShuzoNShuzoN

obsidianにしずかなインターネットで書いた記事を全部移行していく。
markdownは諦めて、記事をそのまま食わせる形を目指す。

domレンダリングさせるのめんどかったのでchorome内consoleでjs書いて内容を取る。headless cli browserで一括で処理するのも考えたがハマったのでめんどかった。

https://sizu.me/shuzon?page=1 で以下を実行する。10ページほどしかなかったのでページネーションは加味せず各ページごとに実行してjsonにコピペする形にした。

chat gptに生成させたインスタントなコード。

(async () => {
  // ① ページ上からパスを動的取得
  const paths = Array.from(
    document.querySelectorAll('article a[href^="/shuzon/posts/"]'),
    a => a.getAttribute('href')
  );

  // ② 重複除去
  const unique = Array.from(new Set(paths));

  // ③ 取得 → 整形
  const base = 'https://sizu.me';
  const articles = await Promise.all(
    unique.map(async path => {
      const res  = await fetch(base + path);
      const html = await res.text();
      const doc  = new DOMParser().parseFromString(html, 'text/html');

      const titleEl = doc.querySelector('h1');
      const title   = titleEl ? titleEl.textContent.trim() : '(タイトルなし)';

      const bodyEl  = doc.querySelector('.post-body_content__42O24');
      const body    = bodyEl
        ? Array.from(bodyEl.querySelectorAll('p'))
               .map(p => p.textContent.trim())
               .filter(Boolean)
               .join('\n\n')
        : '(本文なし)';

      return {
        Path: base + path,
        Title: title,
        Body: body
      };
    })
  );

  // ④ JSONとして出力
  console.log(
    JSON.stringify(
      { articles },
      null,
      2
    )
  );
})();

出力はこんな感じのjsonになる。

{
  "articles": [
    {
      "Path": "https://sizu.me/shuzon/posts/3iuvao7m5t9f",
      "Title": "風を借りる",
      "Body": "内省や省察…"
    },]
}
ShuzoNShuzoN

jsonを各ページごとに作っておいて、各ページの結果を取得する。

これで準備完了。

ShuzoNShuzoN

obsidian を使うのでとりあえずcliを使ってみる

https://github.com/Yakitrak/obsidian-cli

brew tap yakitrak/yakitrak
brew install yakitrak/yakitrak/obsidian-cli

Set Default Vault

Vaultってのは「Obsidianが認識しているファイル置き場」みたいなやつ。 .obsidian という隠しフォルダがあれば挙動する。obsidianからフォルダ作ると自動生成されるはず。

私のVaultは ~/ObsidianValut にあるので

obsidian-cli set-default "ObsidianValut"

にしてみた。

ShuzoNShuzoN

documentを読むと

obsidian-cli create "{note-name}" --content "abcde"

でどうやら記事が作成されるっぽい。つまりjsonをパースしてtitle, bodyをそれぞれ指定すればよしなにやってくれそう。

同ディレクトリに入っているjsonを一括で読んでobsidianに突っ込んでもらうようにした。
(カレントディレクトリの全jsonを読む)

# sizume ディレクトリ配下の全 JSON から articles を集めてマージ→Pathでユニーク化→個別に obsidian-cli を呼び出す

jq -s '
  # 1) slurp で全ファイルを配列に
  # 2) 各ファイルの .articles[] を flat map
  # 3) Path キーで重複排除
  map(.articles // []) | add | unique_by(.Path)
' ./*.json \
| jq -c '.[]' \
| while IFS= read -r article; do
    # 各記事を個別にパース
    title=$(jq -r '.Title' <<<"$article")
    body=$(jq -r '.Body'  <<<"$article")

    # obsidian-cli に渡す
    obsidian-cli create "$title" --content "$body"
  done

コメントが含まれていると実行時にエラーが出るので除去。

jq -s '
  map(.articles // []) | add | unique_by(.Path)
' ./*.json \
| jq -c '.[]' \
| while IFS= read -r article; do
    title=$(jq -r '.Title' <<<"$article")
    body=$(jq -r '.Body'  <<<"$article")

    obsidian-cli create "$title" --content "$body"
  done
ShuzoNShuzoN

jsonに含まれる記事数と結果が2件ほどズレている。

どうもtitleに禁止文字が入ってるとcreateが失敗するようでそれを特定する。
実行時エラーでは「タイトルに/を含む記事は無効」のような感じでエラーが出ていたけど、その文字を含む記事がないため難航。

結論、タイトルに : を含むと実行エラーが出るっぽかった(これが2件あったので件数一致)

見えない谷: 前編 私(I)を超えて私たち(We)で考える
ShuzoNShuzoN

漏れた記事の名前を修正し、sizume_exception.json と名付けて同じ構造で保存。
※先ほどと同じファイルで実行してしまうと記事が重複するため対象記事のみを扱うこと

jq -s '
  map(.articles // []) | add | unique_by(.Path)
' ./sizume_exception.json \
| jq -c '.[]' \
| while IFS= read -r article; do
    title=$(jq -r '.Title' <<<"$article")
    body=$(jq -r '.Body'  <<<"$article")

    obsidian-cli create "$title" --content "$body"
  done

再度、指定ファイルを変えて実行。問題なく動いた

このスクラップは4ヶ月前にクローズされました