質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.96%

Python3とはてなAPIを利用した、はてなフォトライフへの画像アップロードをしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,863

score 13

 前提・実現したいこと

はてなフォトライフのAPIを利用して、Python3とWSSE認証によって、画像をアップロードしたいと考えています。

 発生している問題・エラーメッセージ

Error!
status_code: 500
message: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator,
 root@localhost and inform them of the time the error occurred,
and anything you might have done that may have
caused the error.</p>
<p>More information about this error may be available
in the server error log.</p>
</body></html>

 該当のソースコード

#!/home/pi/.pyenv/shims/python                                                                                                                   
#coding=utf-8                                                                                                                           
import sys
import datetime
import random
import hashlib
import base64

import requests
from chardet.universaldetector import UniversalDetector

import datetime
now = datetime.datetime.now()
dtime = str(now.year)+"""-"""+str(now.month)+"""-"""+str(now.day)+"""T"""+str(now.hour)+""":"""+str(now.minute)+""":"""+str(now.second)
print(dtime)

# setting -----------------------------------------------------------                                                                   
username = '****user'
api_key  = '****accesstoken'
blogname = '****brogname'

# main -----------------------------------------------------------                                                                      
def main():
    data = create_data()
    post_hatena(data)

def wsse(username, api_key):
    created = datetime.datetime.now().isoformat() + "Z"
    b_nonce = hashlib.sha1(str(random.random()).encode()).digest()
    b_digest = hashlib.sha1(b_nonce + created.encode() + api_key.encode()).digest()
    c = 'UsernameToken Username="{0}", PasswordDigest="{1}", Nonce="{2}", Created="{3}"'
    return c.format(username, base64.b64encode(b_digest).decode(), base64.b64encode(b_nonce).decode(), created)

def create_data():
    files = open("./test.png", "rb").read()
    uploadData = base64.b64encode(files)
    template = """                                                                                                                      
    <entry xmlns="http://purl.org/atom/ns#">                                                                                            
    <title>Sample</title>                                                                                                               
    <content mode="base64" type="image/png">"""+str(uploadData)+"""</content>                                                                
    </entry>                                                                                                                            
    """

    data = base64.b64decode(template)
    return data

def post_hatena(data):
    headers = {'X-WSSE': wsse(username, api_key)}
    url = 'http://f.hatena.ne.jp/atom/post/'
    r = requests.post(url, data=data, headers=headers)

    if r.status_code != 201:
        sys.stderr.write('Error!\n' + 'status_code: ' + str(r.status_code) + '\n' + 'message: ' + r.text)

if __name__ == '__main__':
    main()

 試したこと

HTTPやWSSE、requestsモジュール等に関する知識がほぼ無く、何が原因でステータスコード500エラーが出ているのかがあまりよくわかっていません。
はてなサービスにおけるWSSE認証(http://developer.hatena.ne.jp/ja/documents/auth/apis/wsse)
を見た限りでは、認証の仕方に問題はないように思えます。
おそらくcreate_data()関数内のエンコードの仕方に問題があるのではと思っているのですが、いまいち何が間違っているのかよくわかりません。

 補足情報(FW/ツールのバージョンなど)

Raspberry Pi3 B+ (Raspbian)
Python 3.6.6

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

はてなフォトライフAtomAPI

POST /atom/post

<entry xmlns="http://purl.org/atom/ns#">
  <title>Sample</title>
  <content mode="base64" type="image/jpeg">/9j/2wCEAAQDAwQDAw.../9n/AA==</content>
</entry>

    data = base64.b64decode(template)
    return data

base64.b64encode(files)エンコードした後にxml全体をbase64.b64decode(template)でデコードする必要はないような。

発行しているリクエストはHTMLプロキシソフトで確認してみてくださいな。


試しにアップロードしてみた所、以下の箇所も修正する必要がありました。

-str(uploadData)
+uploadData.decode()

書き換えたサンプルコードです、ご参考まで。

# -*- 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

now = datetime.now()
dtime = str(now.year)+"""-"""+str(now.month)+"""-"""+str(now.day)+"""T"""+str(now.hour)+""":"""+str(now.minute)+""":"""+str(now.second)
print(dtime)


username = '****user'
api_key  = '****accesstoken'
blogname = '****brogname'  # ※不要でした。


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>
    </entry>
    """


def post_hatena(data):
    headers = {'X-WSSE': wsse(username, api_key)}
    url = 'http://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}')


def main():
    data = create_data()
    post_hatena(data)


if __name__ == '__main__':
    main()


■参考情報

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/13 13:24

    ご回答ありがとうございます。
    修正いただいたとおりに書くと、アップロードができました。
    大変助かりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る