使用Python3的脚本进行JSON的POST请求

经常有人想用一个简单的Python3脚本进行json的POST请求。

首先是示例代码。

import urllib.request, json

if __name__ == '__main__':
    url = "http://xxxx/xxxx" 
    method = "POST"
    headers = {"Content-Type" : "application/json"}

    # PythonオブジェクトをJSONに変換する
    obj = {"xxx" : "xxxx", 123 : 123} 
    json_data = json.dumps(obj).encode("utf-8")

    # httpリクエストを準備してPOST
    request = urllib.request.Request(url, data=json_data, method=method, headers=headers)
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")

我想要使用”Niconico视频 ‘Snapshot搜索API'”,作为一个简单的示例,从”结月ゆかり”的搜索结果中获取播放量最多的30个视频。

import urllib.request, json

if __name__ == '__main__':
    url = "http://api.search.nicovideo.jp/api/snapshot/"
    method = "POST"
    obj = {
        "query" : "結月ゆかり",
        "service" : ["video"],
        "search" : ["title", "description", "tags"],
        "join" : ["title", "view_counter"],
        "sort_by" : "view_counter",
        "order" : "desc",
        "size" : 30,
        "issuer" : "xxxxxxxxxxxxxxxxxxxxx"
    }
    json_data = json.dumps(obj).encode("utf-8")
    headers = {"Content-Type" : "application/json"}

    request = urllib.request.Request(url, data=json_data, headers=headers, method=method)
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")

        result_objs = json.loads(response_body.split('\n')[0])
        for result_obj in result_objs["values"]:
            print("{0:<10}{1}".format(result_obj["view_counter"], result_obj["title"]))

# 2903887   【初音ミク】こちら、幸福安心委員会です。【オリジナル】
# 2331059   みwなwぎwっwてwきwたwww(篠笛禁断症状L5)
# 1979283   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#1
# 1896978   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#5
# 1805589   【Minecraft】ゆかり「メイジタワー爆破しましょう」part1【VOICEROID+実況】
# 1662622   【結月ゆかり】名前のない怪物を歌ってもらった【PSYCHO-PASS】
# 1617931   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#3
# 1587257   【初音ミク】永遠に幸せになる方法、見つけました。【オリジナル】
# 1531263   【結月ゆかり】幸せになれる隠しコマンドがあるらしい【オリジナル】
# 1499237   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#2
# 1424024   【結月ゆかりの】チュルリラ・チュルリラ・ダッダッダ!
# 1391173   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#7
# 1356847   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#6
# 1354592   【Minecraft】ゆかり「メイジタワー爆破しましょう」part3【VOICEROID+実況】
# 1261669   【Minecraft】ゆかり「メイジタワー爆破しましょう」part2【VOICEROID+実況】
# 1241053   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#8
# 1223469   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#4
# 1201715   【Minecraft】ゆかり「メイジタワー爆破しましょう」part4【VOICEROID+実況】
# 1182955   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ#9
# 1177519   【Minecraft】ゆかり「メイジタワー爆破しましょう」part9【VOICEROID+実況】
# 1069852   【MAYU】一途な片思い、実らせたい小さな幸せ。【オリジナル】
# 1045793   【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ⑩
# 1040149   【Minecraft】ゆかり「メイジタワー爆破しましょう」part5【VOICEROID+実況】
# 1008825   【Minecraft】ゆかり「メイジタワー爆破しましょう」part6【VOICEROID+実況】
# 993675    【結月ゆかりの】サヨナラチェーンソー
# 963262    【Minecraft】ゆかり「メイジタワー爆破しましょう」part7【VOICEROID+実況】
# 927444    【Minecraft】ゆかり「メイジタワー爆破しましょう」part8【VOICEROID+実況】
# 895328    【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ⑫
# 892567    【Minecraft】ゆかり「メイジタワー爆破しましょう」最終回【VOICEROID+実況】
# 878046    【Minecraft】ゲリラクラフト 周囲に防衛線を築き地雷を張り巡らせるんだ⑪

因为有一些注意事项,所以我会简单介绍一下。

    • POSTするデータ、つまりurllib.request.Request()のdataに指定する引数はbytes型である必要があります。要するにstrではだめで、encode()|などを使って変換してやる必要があります。

レスポンスの結果を取得するhttp.client.HTTPResponse#read()の戻り値もbytes型なので、strに変換する場合はdecode()などを利用します。

json.dupms()はPythonオブジェクトをjson文字列(str)に変換してくれます。json.dump()という似たような名前のメソッドもありますが、これは別物です。

同様にjson.loads()とjson.load()も別物です。

urllib.request.urlopen()の戻り値はhttp.client.HTTPResponseです。

bannerAds