Wintus
9/5/2013 - 10:26 AM

はてなブログAtomPub APIを使った簡易投稿クライアントアプリ(http://ottati.hatenablog.com/entry/2013/09/06/190925の解説用)

はてなブログAtomPub APIを使った簡易投稿クライアントアプリ(http://ottati.hatenablog.com/entry/2013/09/06/190925の解説用)

# -*- coding: utf-8 -*-

import base64
import datetime
import hashlib
import random
import requests
import time


USER_NAME = "******"              # はてなID (ex: "ottati")
BLOG_ID = "******.hatenablog.com" # ブログID (ex: "ottati.hatenablog.com")
API_KEY = "**********"            # APIキー ブログ管理画面 => 詳細設定より取得
TEMPLATE = """<?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}</title>
  <author><name>{name}</name></author>
  <content type="text/plain">{content}</content>
  <updated></updated>
  <app:control>
    <app:draft>{draft}</app:draft>
  </app:control>
</entry>
"""


def create_wsse(username, password):
    """X-WSSEヘッダの内容を作成

    ユーザネームとAPIキーからWSSE認証用文字列を作成し、返します。
    
    Args:
        @username: はてなID
        @password: はてなブログで配布されるAPIキー
    Returns:
        WSSE認証用文字列
    """
    
    nonce = hashlib.sha1(str(time.time()) + str(random.random())).digest() # セキュリティトークン
    created = datetime.datetime.now().isoformat() + "Z" # Nonceの作成時刻
    digest = base64.b64encode(hashlib.sha1(nonce+created+password).digest()) # PasswordDigest
    # WSSE認証用文字列として整形して返す
    return 'UsernameToken Username="{0}", PasswordDigest="{1}", Nonce="{2}", Created="{3}"'.format(username, digest, base64.b64encode(nonce), created)


def fix_encoding(string):
    """Shift_JISであればUTF-8に修正する関数"""
    try:
        return string.decode('shift-jis').encode('utf-8')
    except:
        return string
    

if __name__ == "__main__":
    """メイン処理"""
    print u"\nはてぽす! - はてなブログAtomPubを使った簡易投稿アプリ\n"
    title = fix_encoding(raw_input("Title: "))     # タイトル
    content = fix_encoding(raw_input("Content: ")) # 本文
    entry = TEMPLATE.format(
        title = title,          # 記事タイトル
        name = USER_NAME,       # 記事著者
        content = content,      # 記事本文
        draft = "yes"           # 下書きとして投稿 (yes / no)
        )
    url = "http://blog.hatena.ne.jp/{0}/{1}/atom/entry".format(USER_NAME, BLOG_ID) # リクエストURL
    wsse =  create_wsse(USER_NAME, API_KEY) # WSSE認証用文字列
    r = requests.post(url, data=entry, headers={'X-WSSE': wsse}) # POST
    if r.status_code == 201:                                     # 投稿成功判定
        print u"\n投稿しました。" # 成功メッセージ
    else:
        print u"\n投稿に失敗しました。" # 失敗メッセージ