たぶん何番煎じかわからないけど、最小構成Red Hat系OSの上でREST APIを叩く機会があり、手持ちの言語だと追加ライブラリなしで実装できなくてcurlでゴリゴリ書いて凌いだことがあったけど、Pythonだと標準ライブラリでできるらしいので試してみた。
想定している読者
- Pythonは初心者
- 制御構文とか関数とかプログラミングの基本的なことは完全にマスター()
- Pythonの配列とか辞書(連想配列)は何となく知っている
- RESTful APIが何かは知っている
2019.05.29追記: ビジネスプランの場合のAPI利用申請について追記
TL;DR
- Python2.7 (OSインストール後の標準環境はまだ2.7系の模様)
- 追加ライブラリなし
- API Tokenはチャットワークの設定メニューから取得
- HTTPアクセスには標準のurllib2ライブラリを使用
- レスポンスのJSON解析は標準のjsonライブラリを使用
- 今回実行したAPIは以下の2つ
- ルーム一覧の取得(
GET
) - 「マイチャット」にメッセージ投稿(
POST
)
- ルーム一覧の取得(
API Tokenの取得
小難しいOAuthなどは不要。
Webのチャットワークにログインし、設定メニューから「API設定」を選択。
画面にチャットワークのログインパスワードを入力すればTokenの文字列が表示される。
2019.05.29 追記
上記はフリープラン(おそらくパーソナルプランも)の場合。
ビジネスプランの場合は、APIトークンの取得には「管理者」の許諾が必要。
利用申請画面で[API利用申請]ボタン押下すれば、設定されている組織の管理者へ利用申請の通知が届く。
そして管理者が許諾の手続きを行えば、APIトークンが作成可能になる。
(フリープランのときに作っていたAPIトークンがあっても、すべて破棄される)
Pythonのソースコードを書く
大枠
Python2系だとこんな感じ。
ソースコードはutf-8
で書く。
変数の頭に$
とかつかないし、行末の;
もないし、ブレース{...}
はなくてブロックの始まりに:
を書く模様。
mainの書き方が独特ですね。
-
def myfunction(arg):
でmyfunction関数(引数はarg)を定義 -
if __name__ == '__main__':
でメイン関数を定義
#!/usr/bin/python
# -*- coding: utf-8 -*-
def myfunction(arg):
return arg + 1
if __name__ == '__main__':
result = myfunction(arg)
設定ファイル読み込み
API Tokenをソースファイル内にハードコーディングしてもいいけど、せっかくなので外部ファイルに保存し、それをスクリプトから読み込むようにする。
Pythonの標準ライブラリにConfigParser
というものがあり、Windowsのiniファイルに近い形式の設定ファイルを簡単に読み込める。
[chatwork]
token = ********
import ConfigParser
ini = ConfigParser.SafeConfigParser()
ini.read('./config.ini')
token = ini.get('chatwork', 'token')
これでtoken
にはconfig.iniに記述しているtokenの値がセットされる。
「マイチャット」のID取得(GETリクエスト)
解説は見当たらなかったけど「マイチャット」であるかどうかは、チャットのtype
がmy
になっているので、その項目を探す。
チャット一覧を取得するにはhttps://api.chatwork.com/v2/rooms
に対してGETリクエストを投げればOK。
標準ライブラリでHTTPアクセスを行うには、urllib2
を使用する。
- 20.6. urllib2 --- URL を開くための拡張可能なライブラリ — Python 2.7.15 ドキュメント
- urllib2 を使ってインターネット上のリソースを取得するには — Python 2.7.15 ドキュメント
基本的な構文はurllib2.urlopen("http://www.example.org")
となるが、今回はAPI Tokenをヘッダに付加するため、Requestオブジェクトを作成(urllib2.Request()
)し、それにヘッダ設定を追加(request.add_header()
)している。
エラーの場合は例外が発生するのでハンドリングしておく。
レスポンスはJSON形式なので、これもPythonのjson
ライブラリを使って対象を探す。
json.loads()
することで、Pythonの配列・辞書形式のオブジェクトに変換してくれる。(PowerShellのConvertFrom-Json
と同じ!)
チャット一覧は配列形式なのでfor
で地道に探す。
18.2. json --- JSON エンコーダおよびデコーダ — Python 2.7.15 ドキュメント
def get_mychat_id(token):
url = 'https://api.chatwork.com/v2/rooms'
request = urllib2.Request(url)
request.add_header('X-ChatWorkToken', token)
try:
resp = urllib2.urlopen(request)
except urllib2.HTTPError, e:
print e.code
print e.reason
print e.read()
return ""
j = json.loads(resp.read())
for item in j:
if item['type'] == 'my':
room_id = item['room_id']
return room_id
マイチャットへメッセージ送信(POSTリクエスト)
チャットのID取得と同様にurllib2
を使用する。
今回はメッセージの送信のため、HTTPリクエストボディも追加する(request.add_data()
)。
リクエストボディを追加すると、メソッドは勝手にPOSTになる。
リクエストボディはURLエンコードをしておく必要があるため、(urllib2とは別の)urllib
を使用する(urllib.urlencode()
)。
20.5. urllib --- URL による任意のリソースへのアクセス — Python 2.7.15 ドキュメント
def post_message(token, room_id, message):
url = "https://api.chatwork.com/v2/rooms/" + str(room_id) + "/messages"
request = urllib2.Request(url)
request.add_header('X-ChatWorkToken', token)
body = {
'body' : message
}
request.add_data(urllib.urlencode(body))
try:
resp = urllib2.urlopen(request)
except urllib2.HTTPError, e:
print e.code
print e.reason
print e.read()
return ""
print resp.read()
あと、他言語やってたせいで引っかかったのが、intの値(room_idは文字列でなく数値)は+
で文字列連結しようとしても型エラーになるので、明示的にstr()
で文字列にしてやる必要がある。
ソース全体
チャットワークはGoogle APIと違って日本語がそのまま送れました。。𩸽も問題なし。
(念のためPowerShellでも書いてみたけどShift_JISのソースコードなら問題なかった。𩸽は?
になったけど)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import ConfigParser
import urllib
import urllib2
import json
def read_token():
ini = ConfigParser.SafeConfigParser()
ini.read('./config.ini')
return ini.get('chatwork', 'token')
def get_mychat_id(token):
url = 'https://api.chatwork.com/v2/rooms'
request = urllib2.Request(url)
request.add_header('X-ChatWorkToken', token)
try:
resp = urllib2.urlopen(request)
except urllib2.HTTPError, e:
print e.code
print e.reason
print e.read()
return ""
j = json.loads(resp.read())
for item in j:
if item['type'] == 'my':
room_id = item['room_id']
return room_id
def post_message(token, room_id, message):
url = "https://api.chatwork.com/v2/rooms/" + str(room_id) + "/messages"
request = urllib2.Request(url)
request.add_header('X-ChatWorkToken', token)
body = {
'body' : message
}
request.add_data(urllib.urlencode(body))
try:
resp = urllib2.urlopen(request)
except urllib2.HTTPError, e:
print e.code
print e.reason
print e.read()
return ""
print resp.read()
if __name__ == '__main__':
token = read_token()
#print token
id = get_mychat_id(token)
print id
post_message(token, id, "hello chatwork api!\n日本語\n改行も多バイトコードもそのまま書ける…?\nほっけ / 𩸽 / ホッケ")
※ urlopen()の例外はハンドリングしてるけど、そのあとは素通りしているので注意