2016年3月2日水曜日

Google API を利用して Python2.7 スクリプトから Google Blogger へ投稿

Ubuntu 15.10 には python3-googleapi というパッケージがあり、これを使うと Python3 スクリプトから Google Blogger に投稿できるはずなのですが、途中でエラーとなりいまいち解決方法がわかりませんでした。

なので今回は Python2.7 スクリプトから Google API を利用して Gooble Blogger へ投稿してみました。OS はいつもどおり Ubuntu 14.04 LTS です。


環境

  • Ubuntu 14.04 Server
  • Python 2.7.6

Blogger API V3 を有効にする

スクリプトから Blogger へ投稿するために Google API を使うには、スクリプトを OAuth 2.0 で Google に認証してもらう必要があります。まずは Blogger 用 Google API を有効にして OAuth 2.0 認証情報を Google から取得します。


Google デベロッパーコンソールにアクセス

プロジェクトを作成

  • プロジェクト名: (任意)
  • App Engine の場所: us-central (デフォルトのまま)

Blogger API V3 を有効化

  • デベロッパーコンソールで作成したプロジェクトの API Manager に移動
    • Google デベロッパーコンソールの画面左上をクリックすると出てくるメニューで「API Manager」をクリック
  • 「概要」タブをクリック
  • API 検索ボックスに「Blogger」を入力
  • 「Blogger API V3」をクリック
  • 「API を有効にする」をクリック
  • 「有効な API」に「Blogger API V3」が追加されました。
  • 他にもいろいろな API がデフォルトで有効になっていますが、必要なさそうなので「Blogger API V3」以外は無効にしておきます。

OAuth 同意画面を設定

  • API Manager の画面で「認証情報」タブの中の「OAuth 同意画面」をクリック
  • 「ユーザーに表示するサービス名 」を設定 (必須の設定のようです)
  • その他の項目も必要に応じて設定
  • 「保存」をクリック

認証情報を設定

  • API Manager の画面で「認証情報」タブの中の「認証情報」をクリック
  • 「新しい認証情報」のドロップダウンから「OAuth クライアント ID」を選択
  • アプリケーションの種類で「その他」を選択
  • クライアント名を入力
  • 「作成」をクリック
  • 「クライアント ID」と「クライアント シークレット」が作成されました。

Ubuntu 側の準備

Google API モジュールをインストール

$ sudo apt-get install python-googleapi

クライアント シークレット JSON ファイルを配置

Google API Manager からクライアントシークレット JSON ファイル client_secret_...json (省略してますが、かなり長いファイル名です) をダウンロード

ダウンロードした client_secret_...json を some/where/client_secret.json として配置

クレデンシャル情報保存用のテンポラリなファイルを作成

$ touch some/where/tmp_credentials

これらのファイルは他の人に見られるのは良くなさそうなので、アクセス権を変更

$ chmod 600 some/where/client_secret.json some/where/tmp_credentials
  • これはとりあえずの chmod ですが、心配であればさらに厳しいアクセス制限をお勧めします。

Python2.7 から Gloogle Blogger API へアクセス

Python2.7 を起動

$ python2.7
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

モジュールをインポート

>>> from oauth2client import client
>>> from apiclient.discovery import build
>>> import httplib2
>>> from pprint import pprint

tmp_credentials ファイルからクレデンシャル情報 (oCredentials) を取得

>>> def getCredentialsFromFile():
...     with open('some/where/tmp_credentials') as oFileCredentials:
...         sCredentials = oFileCredentials.read()
...
...     try:
...         oCredentials = client.OAuth2Credentials.from_json(sCredentials)
...     except:
...         return None
...
...     if oCredentials.invalid:
...         return None
...
...     return oCredentials
...
>>> oCredentials = getCredentialsFromFile()
  • 初めてこのコードを実行する場合は tmp_credentials は空ファイルなので oCredentials は None となります。
  • 2度目以降は tmp_credentials から読み込んだクレデンシャル情報が oCredentials にセットされます。

tmp_credentials ファイルからクレデンシャル情報を取得できなかった場合は OAuth2 で Google API からクレデンシャル情報を取得

>>> if oCredentials is None:
...     oFlow = client.flow_from_clientsecrets(
...         'some/where/client_secret.json',
...         scope='https://www.googleapis.com/auth/blogger',
...         redirect_uri='urn:ietf:wg:oauth:2.0:oob'
...     )
...     sAuthUrl = oFlow.step1_get_authorize_url()
...     print(sAuthUrl)
...
https://accounts.google.com/o/oauth2/auth?scope=...

表示された URL にブラウザでアクセスし、得られた認証コードを以下のように入力

>>> if oCredentials is None:
...     sAuthCode = raw_input('Authorization code: ')
...     oCredentials = oFlow.step2_exchange(sAuthCode)
...
...     with open('some/where/tmp_credentials', 'r+') as oFileCredentials:
...         oFileCredentials.truncate(0)
...         oFileCredentials.write(oCredentials.to_json())
...
Authorization code: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

クレデンシャル情報 (oCredentials) を取得することができたので Blogger サービスオブジェクト (oBloggerService) を取得

>>> oHttp = httplib2.Http()
>>> oHttp = oCredentials.authorize(oHttp)
>>> oBloggerService = build(serviceName='blogger', version='v3', http=oHttp)

ユーザー情報を表示

>>> oUsers = oBloggerService.users()
>>> dUser = oUsers.get(userId='self').execute()
>>> pprint(dUser)
{u'about': u'',
 u'blogs': {u'selfLink': u'https://www.googleapis.com/blogger/v3/users/XXXXXXXXXXXXXXXXXXXXXX/blogs'},
 u'displayName': u'Shrimper Fish',
 u'id': u'XXXXXXXXXXXXXXXXXXXXXX',
 u'kind': u'blogger#user',
 u'selfLink': u'https://www.googleapis.com/blogger/v3/users/XXXXXXXXXXXXXXXXXXXXXX',
 u'url': u'https://www.blogger.com/profile/YYYYYYYYYYYYYYYYYYYY'}

ブログ情報を表示

>>> oBlogs = oBloggerService.blogs()
>>> dBlogs = oBlogs.listByUser(userId='self').execute()
>>> pprint(dBlogs)
{u'items': [{u'description': u'',
             u'id': u'ZZZZZZZZZZZZZZZZZZZ',
             u'kind': u'blogger#blog',
             u'locale': {u'country': u'',
                         u'language': u'ja',
                         u'variant': u''},
             u'name': u'IT とかその他もろもろ',
             u'pages': {u'selfLink': u'https://www.googleapis.com/blogger/v3/blogs/ZZZZZZZZZZZZZZZZZZZ/pages',
                        u'totalItems': 0},
             u'posts': {u'selfLink': u'https://www.googleapis.com/blogger/v3/blogs/ZZZZZZZZZZZZZZZZZZZ/posts',
                        u'totalItems': 126},
             u'published': u'2012-03-23T22:19:00+09:00',
             u'selfLink': u'https://www.googleapis.com/blogger/v3/blogs/ZZZZZZZZZZZZZZZZZZZ',
             u'status': u'LIVE',
             u'updated': u'2016-02-18T02:47:00+09:00',
             u'url': u'http://fishrimper.blogspot.com/'}],
 u'kind': u'blogger#blogList'}
  • Python2.7 の pprint で日本語を表示しようとすると文字化けするので修正しています。

記事を投稿するブログの ID を取得

>>> sID = dBlogs['items'][0]['id']
>>> sID
u'ZZZZZZZZZZZZZZZZZZZ'

記事を投稿

>>> dBody = {
...     'title': 'Test Title',
...     'content': '<div>Test Content</div>'
... }
>>> oPosts = oBloggerService.posts()
>>> dResult = oPosts.insert(blogId=sID, body=dBody, isDraft=True).execute()
>>> pprint(dResult)
{u'author': {u'displayName': u'Shrimper Fish',
                         u'id': u'XXXXXXXXXXXXXXXXXXXXXX',
                         u'image': {u'url': u'//XXX.googleusercontent.com/XXXXXXXXXX/AAAAAAAAAAI/AAAAAAAAAMc/XXXXXXXX/XXXXX/photo.jpg'},
                         u'url': u'https://www.blogger.com/profile/YYYYYYYYYYYYYYYYYYYY'},
 u'blog': {u'id': u'ZZZZZZZZZZZZZZZZZZZ'},
 u'content': u'<div>Test Content</div>',
 u'etag': u'"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"',
 u'id': u'XXXXXXXXXXXXXXXXXX',
 u'kind': u'blogger#post',
 u'published': u'2016-02-19T13:26:00+09:00',
 u'readerComments': u'ALLOW',
 u'replies': {u'selfLink': u'https://www.googleapis.com/blogger/v3/blogs/ZZZZZZZZZZZZZZZZZZZ/posts/XXXXXXXXXXXXXXXX/comments',
                          u'totalItems': u'0'},
 u'selfLink': u'https://www.googleapis.com/blogger/v3/blogs/ZZZZZZZZZZZZZZZZZZZ/posts/XXXXXXXXXXXXXXXXXXXXXXXX',
 u'status': u'DRAFT',
 u'title': u'Test Title',
 u'updated': u'2016-02-19T13:26:33+09:00',
 u'url': u'http://fishrimper.blogspot.com/'}

dBody の内容が草稿として Blogger に投稿されました。





参考


0 件のコメント:

コメントを投稿