マストドンのアーカイブをcsv形式にするコード

  mastodon-japan.netサーバーが閉鎖されるとのことなので、アーカイブをダウンロードした。その中に、outbox.jsonがあった。これはテキストエディタで開くには重すぎる。ただし、Windowsの「メモ帳」なら開ける。このoutbox.jsonから重要なデータを抽出してcsv形式にすることにした。jqというものを利用した。

https://jqlang.org/

 このコードについては全く分からないので、Geminiにコードを作成してもらった。

 to_csv.jq というファイルと to_csv.bat というファイルを作成して同じディレクトリーに置き、to_csv.bat を実行すると mastodon_data.csv というファイルが同じディレクトリーに作られる。

 画像などの添付ファイルについては、アーカイブのzipファイルの media_attachments フォルダーの中のかなり深い階層に収納されていて、その位置は outbox.json に記載されているので、その位置も抽出することにした。投稿のidと日時とactorとコンテンツとinReplyToと画像などの添付ファイルを抽出したのだが、idとactorはURL形式だった。

 また、コンテンツに「"」や「,」が含まれている場合が心配だったが、Geminiによると、「ご使用になった jq のフィルタには、CSVの標準ルールに従ってこれらを自動で処理する仕組みが組み込まれていますので、基本的に列がずれる心配はありません。」とのことだった。最終行の@csv 演算子のおかげらしい。

この @csv 演算子が非常に重要で、以下の標準的なCSVルールに従ってデータを安全にエンコードします。

  1. カンマ (,):(Geminiの嘘。実際は,のまま。""で囲まれているから,のままで大丈夫)

    • データフィールド内にカンマが含まれている場合、そのフィールド全体は二重引用符 (") で括られます。

    • 例: あ,い,う"あ,い,う"

  2. 二重引用符 ("):(Geminiの嘘。実際は")

    • データフィールド内に二重引用符が含まれている場合、そのフィールド全体は二重引用符で括られ、さらにフィールド内の二重引用符は二つ重ねてエスケープされます。

    • 例: 「これは"引用"だ」"「これは""引用""だ」"

あなたのcontent_textは、抽出前に以下の処理が施されています。

  1. HTMLタグの削除: clean_content 関数で <p>, <a href> などのHTMLタグが削除されます。

  2. 改行の置換: clean_content 関数で、改行文字 (\r, \n) がスペースに置換されます。

  3. CSVエスケープ: 最後に @csv 演算子により、残ったカンマや二重引用符が上記のルールで安全にエンコードされます。

これにより、ExcelやGoogle SheetsなどのCSV対応ソフトウェアでファイルを開いたときに、データがずれることなく、一つのセルに正しく収まりますので、ご安心ください。

  さて、コードは次の通り。

to_csv.jq

# HTMLタグを削除し、nullを安全に処理する関数
def clean_content: 
    (. // "") | gsub("<[^>]*>"; "") | gsub("[\"\\r\\n]"; " "); 

# 日時変換関数を、エラー回避と正確な日時変換を両立する形に修正
def to_jst: 
    # 1. publishedキーの値が文字列であるか確認し、違えば "" を返す
    if (type != "string") or (. == null) then 
        "" 
    else
        # 2. 変換ロジック
        (
            fromdateiso8601 
            # UTCとしてパースされるため、JSTに直すため +32400 (9時間) を加算
            + 32400 
            # ★★★ ここを修正:秒 (%S) を追加 ★★★
            | strftime("%Y/%m/%d %H:%M:%S")
        ) 
        # 3. 変換全体が失敗した場合(異常データ)は空文字列を返す
        // ""
    end;

# 添付ファイルURLを抽出・結合する関数
def extract_attachments:
    .object.attachment 
    | map(.url // "")
    | join(" | ");

# CSV整形ロジックを定義
def format_csv:
    # アクティビティのタイプで分岐
    if .type == "Create" and (.object | type == "object") then
        # 1. オリジナル投稿 (Create) の場合
        [
            (.object.id // ""),
            (.published | to_jst // ""),
            (.actor // ""),
            (.object.content | clean_content),
            (.object.inReplyTo // ""),
            (extract_attachments)
        ]
    elif .type == "Announce" then
        # 2. リブログ (Announce) の場合
        [
            (.id // ""),
            (.published | to_jst // ""),
            (.actor // ""),
            "リブログ: " + (.object // ""),
            "",
            ""
        ]
    else
        # 3. その他のアクティビティ
        null
    end
    | select(.) | @csv;

# orderedItems配列を展開し、各投稿を処理
.orderedItems[] | format_csv 

 

 to_csv.bat

chcp 65001 > nul
@echo off

:: jq実行ファイルのフルパス
set JQ_PATH="C:\Programs\jq-windows-amd64.exe"
:: 入力ファイル
set IN_FILE="outbox.json"
:: 出力ファイル
set OUT_FILE="mastodon_data.csv"
:: フィルタファイル
set JQ_FILTER="to_csv.jq"

echo JSONからCSVへの変換を開始します...
echo.

:: 1. ヘッダーをCSVファイルに出力 (attachments列を追加)
echo id,published_jst,actor,content_text,inReplyTo,attachments > %OUT_FILE%

:: 2. jqを実行し、結果をファイルに追記 (>> を使う)
%JQ_PATH% -r -f %JQ_FILTER% %IN_FILE% >> %OUT_FILE%

echo.
echo ===================================================
echo ✅ 処理が完了しました。CSVファイルを確認してください。
echo ===================================================
pause 

コメント