やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

PythonでOAuth2.0とFusionTablesAPIによるinsertができた

ついに成功した。前回のエラーはURLパラメータで引数を渡すことで解決した。(POSTなのに)

目標

ラズパイのCPU温度を定期的にロギングしてアップロードしたい

小目標

PythonからFusionTablesAPIを使ってinsertする。

前回

サンプルコードにv2のAPIを叩くコードを追記した

POSTデータにパラメータを付与したつもりが、付与されていないエラー。

今回

小目標を達成した。

前回のエラーはGETと同じ方法のURLパラメータにて与することで解決した。POSTデータで与える方法は不明のまま。

対象環境

原因調査

printで確認

前回のコードのPOSTデータが不正だったのかもしれない。

printで表示してみると以下の通り。

{
      "sql": "INSERT INTO {TableId} (Timestamp, CpuTemperature) values('2011-11-11 11:11:11',11111)"
    }

sqlパラメータはある。問題なさそう。

名前付きパラメータで名前指定して渡す

関数定義はdef runRequest(self, method, url, data=None, headers=None):になっている。でも、呼出は以下のようになっている。

    response = self.runRequest(
      "POST",
      "/fusiontables/v2/query%s" % \
       (self.params),
      data,
      headers={'Content-Type':'application/json'})

data=data,にすべきなのかも?python2の名前付きパラメータの作法とか知らないけど。

    response = self.runRequest(
      "POST",
      "/fusiontables/v2/query%s" % \
       (self.params),
      data=data,
      headers={'Content-Type':'application/json'})

上記のように修正して、再度実行。

同様のエラーになった。

copy and paste the url below into browser address bar and hit enter
https://accounts.google.com/o/oauth2/auth?client_id={*.apps.googleusercontent.com}&redirect_uri=http://localhost:8000&scope=https://www.googleapis.com/auth/fusiontables&response_type=code

Enter code (parameter of URL): 4/2Oa9_jXlIQ1IwOl3-lQOfKH_yXGEv53nxgHLZucZIqA
v2 Query.sql insert
400 Bad Request
{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Required parameter: sql",
    "locationType": "parameter",
    "location": "sql"
   }
  ],
  "code": 400,
  "message": "Required parameter: sql"
 }
}

{u'error': {u'code': 400, u'message': u'Required parameter: sql', u'errors': [{u'locationType': u'parameter', u'domain': u'global', u'message': u'Required parameter: sql', u'reason': u'required', u'location': u'sql'}]}}

GETのように渡す

もういっそ、GETのようにURLパラメータで渡してしまおう。できるかどうか知らないけど。POSTの意味ないけど。

ソースコード修正

  def testInsertV2(self):
    print "v2 Query.sql insert"
    sql = "INSERT INTO %s (Timestamp, CpuTemperature) values('%s',%s)" % (tableid, '2011-11-11 11:11:11',11111)
    data = '''{
      "sql": "%s"
    }''' % (sql)
    print(data)

    response = self.runRequest(
      "POST",
      "/fusiontables/v2/query%s&sql=%s" % \
       (self.params, urllib.quote(sql)),
      data=data,
      headers={'Content-Type':'application/json'})
    json_response = simplejson.loads(response)
    print(json_response)
    return json_response

実行

成功!!!

$ python SimpleSample.py
copy and paste the url below into browser address bar and hit enter
https://accounts.google.com/o/oauth2/auth?client_id={*.apps.googleusercontent.com}&redirect_uri=http://localhost:8000&scope=https://www.googleapis.com/auth/fusiontables&response_type=code

Enter code (parameter of URL): 4/4HgD872blsIW5MR_Frqkz173hkVK92ZXSwHzGNPp9j4
v2 Query.sql insert
200 OK
{
 "kind": "fusiontables#sqlresponse",
 "columns": [
  "rowid"
 ],
 "rows": [
  [
   "41"
  ]
 ]
}

{u'kind': u'fusiontables#sqlresponse', u'rows': [[u'41']], u'columns': [u'rowid']}

たぶんPOSTでデータを渡せていなかったのだろう。URLパラメータでも渡せるものだったのか。それともQuery.sqlだけの仕様なのか。

テーブル確認

本当にデータが追加されているか確認する。

Google Driveにアクセスして、該当のFusion Tablesファイルを開く。追加されていた!

f:id:ytyaru:20161129212849p:plain

課題

  • セキュリティ的にせめてAPIKey, AccessTokenだけでもPOSTデータに含めるべき
  • 再現できるように手順をまとめたい
  • ソースコードの完全版を用意したい
  • 手入力のところの許可を押下するところは、自動化すべきでないのだろう。でも、どうにか自動化できないか

結論

自動化できない。Fusion Tablesへのinsertをcronで実行することはできない。OAuth2.0の手続きがあるかぎり。

所感

ついにできた!

長かった。Fusion Tables APIに触ってみたときの失敗にはじまり、GASのdoGet関数をPythonで叩くからの妥協。失敗の連続。

日付 記事
1/3 GASでFusionTablesAPIを叩いてみた
1/5 GASのdoGet関数でFusionTablesAPIを叩く
1/6 GASのdoGet関数をPythonで叩く
1/8 Google API Client Libraryをインストールした
1/9 GoogleApiClientライブラリにAPIKeyを渡すもエラー
1/10 OAuthとFusionTablesAPIのPythonサンプルコードを試すも失敗
1/11 ローカルサーバを立ち上げてOAuth2.0認証に挑むも失敗
1/12 Unauthorizedエラーの原因はClientSecretのコピペミスが原因だった
1/13 コピペミスを直すもParse Error発生
1/14 サンプルコードにv2のAPIを叩くコードを追記した
1/15 PythonでOAuth2.0とFusionTablesAPIによるinsertができた

私、本当にお疲れ様でした。Fusion Tables APIを使うのにどれだけ苦労させられたことか。しかも自動化できないなんて…。手入力が想像以上に面倒。ローカルサーバを立てる必要まである。おまけにリクエスト上限や時間あたりの登録件数上限、ファイルサイズ上限など各種の制限もある。一体どこまで使えるのか。それを考えるのも大変そう。