0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

cURLではてなブログに投稿してみよう

Posted at

はじめに

この記事はUdon Advent Calendar 2025 - Adventarの5日目の記事です。

続・ブログの投稿をコマンドで

前編に引き続き、ブログへの投稿をコマンドラインからやってみようという趣旨の企画です。

APIリファレンスを参考にやってみよう

公式APIリファレンスに「ブログエントリの投稿」という項目がありました。これを参考にしてみましょう。

記事を投稿して即公開する場合、以下のようにすればよいようです。

POST https://blog.hatena.ne.jp/[はてなID]/[ブログID]/atom/entry

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
       xmlns:app="http://www.w3.org/2007/app">
  <title>[エントリタイトル]</title>
  <author><name>name</name></author>
  <content type="text/plain">
    [エントリ本文]
  </content>
  <category term="[カテゴリ名]" />
</entry>

[]で囲われたところを実際に編集します。

予約投稿をしたり、下書き状態にしたい場合は以下を追加するみたいです。

<updated>2008-01-01T00:00:00</updated>
<app:control>
    <app:draft>{yes | no}</app:draft>
    <app:preview>{yes | no}</app:preview>
</app:control>

では実際にcURLコマンドを用いてこれを実行してみます。

XMLを記入して適当に保存します。その後、以下を実行します。

curl -X POST \
  -H "Content-Type: application/atom+xml" \
  -u "[はてなID]:[APIキー]" \
  -d @test.xml \
  https://blog.hatena.ne.jp/[はてなID]/[ブログID]/atom/entry

リファレンスに直接書いていない点では、以下の事に注意が必要です。

  • -Hオプションでコンテンツタイプの指定が必要
  • -uオプションでベーシック認証が必要(ほかの認証方法もあるらしい)
  • -dオプションでXMLファイルの位置を指定する

結果は以下のようになりました。レスポンスもXMLで返ってくるようです。

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
       xmlns:app="http://www.w3.org/2007/app">
<id>tag:blog.hatena.ne.jp,2013:blog-[はてなID]-4207112889937937851-[記事ID]</id>
<link rel="edit" href="https://blog.hatena.ne.jp/[はてなID]/[ブログID]/atom/entry/[記事ID]"/>
<link rel="alternate" type="text/html" href="https://[ブログID]/entry/2025/12/04/104850"/>

<author><name>[はてなID]</name></author>
<title>テスト</title>
<updated>2025-12-04T10:48:50+09:00</updated>
<published>2025-12-04T10:48:50+09:00</published>
<app:edited>2025-12-04T10:48:50+09:00</app:edited>
<summary type="text">テスト</summary>
<content type="text/x-markdown">    テスト  </content>
<hatena:formatted-content type="text/html" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">&lt;pre&gt;&lt;code&gt;テスト
&lt;/code&gt;&lt;/pre&gt;
</hatena:formatted-content>

<category term="その他" />

<app:control>
  <app:draft>no</app:draft>
  <app:preview>no</app:preview>
</app:control>

</entry>

自分のブログをチェックすると、以下のように投稿されていることがわかります。

1.png

cURL実行用プログラムの作成

さて、前編と同様に、このcURLコマンドを自分で作って実行するのはいささか面倒なので、プログラムに代行してもらいましょう。

今回も以下のようなプログラムをPythonで作成しました。

import os
import json
import dotenv


def read_file(file_path: str) -> str:
    with open(file_path, "r", encoding="utf-8") as f:
        return f.read()


def build_xml(post_content: str, info_json: dict) -> str:
    title = info_json.get("title", "Untitled")
    categories = info_json.get("categories", [])
    draft = info_json.get("draft", "no")
    category_tags = "".join(
        [f'<category term="{category}"/>' for category in categories]
    )
    xml_content = (
        f'<?xml version="1.0" encoding="utf-8"?>'
        f'<entry xmlns="http://www.w3.org/2005/Atom" '
        f'xmlns:app="http://www.w3.org/2007/app">'
        f"<title>{title}</title>"
        f"{category_tags}"
        f'<content type="text/markdown">{post_content}</content>'
        f"<app:control>"
        f"<app:draft>{draft}</app:draft>"
        f"</app:control>"
        f"</entry>"
    )
    return xml_content


def make_curl_command(
    hatena_id: str,
    blog_id: str,
    hatenablog_api_key: str,
    post_content: str,
    info_json: str,
) -> str:
    curl_command = (
        f'curl -X POST "https://blog.hatena.ne.jp/{hatena_id}/{blog_id}/atom/entry" '
        f'-H "Content-Type: application/json" '
        f'-u "{hatena_id}:{hatenablog_api_key}" '
        f"-d '{build_xml(post_content, info_json)}'"
    )
    return curl_command


def main():
    hatena_id = os.getenv("HATENA_ID")
    blog_id = os.getenv("BLOG_ID")
    hatenablog_api_key = os.getenv("HATENABLOG_API_KEY")
    post_content = read_file(
        os.path.join(os.path.dirname(__file__), "..", "data", "post.md")
    )
    info_json = json.loads(
        read_file(
            os.path.join(
                os.path.dirname(__file__), "..", "data", "hatenablog_info.json"
            )
        )
    )
    curl_command = make_curl_command(
        hatena_id, blog_id, hatenablog_api_key, post_content, info_json
    )
    os.system(curl_command)


if __name__ == "__main__":
    dotenv.load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env"))
    main()

処理の流れは以下のようになっています。

  1. 環境変数から必要な情報を取得する
  2. 投稿内容(マークダウン)を読み取る
  3. 投稿情報をJSONファイルから読み取る
  4. cURLコマンドを生成する
  5. 生成したcURLコマンドを実行して記事を投稿する

また、投稿情報を格納するJSONファイルは以下のようになっています。

{
    "title": "テスト",
    "category": "その他",
    "draft": "no"
}

実行

実行時にはディレクトリ構成を以下のようにしておきます。

.
├── .env
├── data/
│   ├── hatenablog_info.json
│   └── post.md
└── src/
    └── post_to_hatenablog_with_curl.py

実行方法は以下の通りです。

  1. .envにはてなID、ブログID、APIキーを記入する
  2. post.mdに記事の内容をコピペする
  3. hatenablog_info.jsonの内容を書き換える
  4. post_to_hatenablog_with_curl.pyを実行する

これによって、作成した記事を投稿することができます!

実際に実行した結果が以下です。自分のブログに投稿されていることがわかります。

2.png

このプログラムはこのリポジトリに置きました。クローンすると使えるはずなので是非やってみてください!

おわりに

Qiitaに続いて、はてなブログでもcURLを用いて記事の投稿ができました。こちらではXMLを扱わなくてはならないので少し難しかったですが、一度プログラムに落としてしまえば記事本体と投稿情報をいじればいいので簡単ですね。

それではまた、明日の記事でお会いしましょう!

参考文献

curl コマンドの基本

はてなブログAtomPub | Hatena Developer Center

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?