(O+P)ut

アウトプット



(O+P)ut

エンジニアのアウトプット

【はてなフォトAPI】ローカルにあるpng画像を指定してアップロードするPythonコード

スポンサーリンク

はじめに

はてなブログの自動投稿は以下で記事にしましたが

写真投稿も自動で行うことで自動投稿の中に新規画像を入れ込むためにPythonコードでのアップロードをテストしました。

環境情報
# python3.6 --version
Python 3.6.3

Pythonコード

以下コードのidにはてなID、api_keyにはてなブログの詳細設定で確認できるAPIキーを入力します。
またFotolife > My fotolife > tmp というフォルダに格納するようにしていますが、それ以外の場所に配置する場合はその部分を修正します。

# -*- coding: utf-8 -*-
from base64 import b64encode
from datetime import datetime
from hashlib import sha1
import random
import requests
import sys
from pathlib import Path
username = 'XX'
api_key  = 'XX'
def wsse(username: str, api_key: str) ->str:
    created = datetime.now().isoformat() + "Z"
    b_nonce = sha1(str(random.random()).encode()).digest()
    b_digest = sha1(b_nonce + created.encode() + api_key.encode()).digest()
    return f'UsernameToken Username="{username}", PasswordDigest="{b64encode(b_digest).decode()}", Nonce="{b64encode(b_nonce).decode()}", Created="{created}"'
def create_data(file_name: str='./test.png') ->str:
    uploadData = b64encode(Path(file_name).read_bytes())
    return """
    <entry xmlns="http://purl.org/atom/ns#">
    <title>Sample</title>
    <content mode="base64" type="image/png">""" + uploadData.decode() + """</content>
    <generator>tmp</generator>
    </entry>
    """
def post_hatena(data):
    headers = {'X-WSSE': wsse(username, api_key)}
    url = 'https://f.hatena.ne.jp/atom/post/'
    r = requests.post(url, data=data, headers=headers)
    try:
        r.raise_for_status()
    except:
        sys.stderr.write(f'Error!\nstatus_code: {r.status_code}\nmessage: {r.text}')
    print('text       = ' + r.text)
def main():
    data = create_data()
    post_hatena(data)
if __name__ == '__main__':
    main()

実行結果

上記スクリプトを引数なしで実行すると標準出力にて以下が応答で返ってきます。

text       = <?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">
  <title>Sample</title>
  <link rel="alternate" type="text/html" href="http://f.hatena.ne.jp/xx/yy"/>
  <link rel="service.edit" type="application/x.atom+xml" href="http://f.hatena.ne.jp/atom/edit/yy" title="Sample"/>
  <issued>...</issued>
  <author>
    <name>xx</name>
  </author>
  <generator url="http://f.hatena.ne.jp/" version="1.0">Hatena::Fotolife</generator>
  <dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">tmp</dc:subject>
  <id>tag:hatena.ne.jp,2005:fotolife-xx-yy</id>
  <hatena:imageurl>https://cdn-ak.f.st-hatena.com/images/fotolife/m/xx/yy.png</hatena:imageurl>
  <hatena:imageurlmedium>https://cdn-ak.f.st-hatena.com/images/fotolife/m/xx/yy_120.jpg</hatena:imageurlmedium>
  <hatena:imageurlsmall>https://cdn-ak.f.st-hatena.com/images/fotolife/m/xx/yy_m.jpg</hatena:imageurlsmall>
  <hatena:syntax>f:id:xx:yyp:image</hatena:syntax>
</entry>

XXで囲まれた情報を利用して以下のように入力することで同画像が利用できます。

[f:id:xx:yyp:plain]

終わりに

モジュールがない場合は以下のようなエラーとなるため

# python3.6 test.py
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    import requests

個別に対応しました。

# pip3.6 install requests

あとはネット上にてサンプルコードがありましたが、Pythonのバージョンやhttps通信指定など細かな修正があったので今回は3.6で動作したコードをそのまま載せています。

ご参考ください。