前書き
- 大学2年生の秋から開発エンジニアになりたいと思い、プログラミングの独学を開始。
- 2017年8月サーバーエンジニアとして入社しました。Railsで開発しております。
- 初めて、Pythonでの開発をしました。
- プログラミング初心者のときから、Qiitaを読んでいて、わかりやすい記事を書きたいなっていつかずっと思ったので、わかりやすく書こうと思います。(その分、長くなりますが、ご理解いただければ幸いです。)
- ここでは、使っているAPIやモジュールについて、書こうと思います。
- 全てのコードは、 githubに載せていて、urlを貼ってあるので、コードをみたい方は下まで移動していただければ、幸いです。
記事を書こうと思った理由
- ある日、2017年の7月までPHP開発のインターン生として働いている会社のslackのrandomチャンネルにて
こうして、写真Botを作ることになったが、難しい...と思ったのは、このとき、まだまだ先の話...。 詰まったことが多いので、記事にしてみることにしました。(Pythonで書く理由は、個人的に書いたことない言語だったので、勉強したいと思ったとの、CTOがPythonが好きだからです笑)
ゴール
下の写真のように、galleryというbotを呼び出し、gallery
と入力したあと、写真がslackに流れるようにすればおkです!
一つ一つ処理を見ていきましょう。
手順
- Slackで、botユーザーを作成
- Pythonで実装されたBotライブラリをインストール
- gdataのmoduleをインストール
- Google Auth認証(Google Photoから写真を取得)
- RtmbotとSlack APIを使って、Slackに文章と写真を投稿。
開発環境
- Python 2.7 (pyenvで開発環境を整えましょう)
- Amazon EC2
1. SlackでBotユーザーを作成
まずは、Slack Appsのページで、Botユーザーを作成をします。
赤い長方形で書いたものは、botのトークンなので、どこか別の場所にコピーしましょう。
2. Pythonで実装されたBotライブラリをインストール
オープンソースのBot管理ライブラリをpip経由で、インストール(https://github.com/slackapi/python-rtmbot)
$ pip install rtmbot
そのあと、rtmbot.confを作成し、下のように編集していきます。
# Add the following to rtmbot.conf
DEBUG: True # make this False in production
# 1.のときに作成したBotのトークンをここに書いてください。
SLACK_TOKEN: "xoxb-11111111111-222222222222222"
# ここには、Botのパスを書いてください。(ディレクトリの名前の間には、/ではなく、 . を書きましょう。)
ACTIVE_PLUGINS:
- plugins.google_photo_to_slack.GooglePhotoToSlackBot
3. gdataのmoduleをインストール
$ pip install gdata
4. Google OAuth認証(Google Photoから写真を取得)
ここでは、Google OAuth2.0認証のやり方を説明します。
Google Cloud PlatformDashboard->Use Google APIs->Credentialsの順番で、OAuth2.0 Client
ID を作成し、そのsecret json ファイルをダウンロードします。タイプは、「その他」を選択してください。

いろいろと、ファイルが増えてきたなかで、ディレクトリ構造は下のようになります。
credentials.dat
の中身は今のところ、何も書かなくて大丈夫です。
rtmbot
├── photo-gallery.json
├── credentials.dat
├── plugins
│ ├── __init__.py
│ └── google_photo_to_slack.py
├── rtmbot.conf
└── rtmbot.log
最初は、ログインを確かめるために、下のように書いてみましょう。
下のファイルに書かれてあるモジュールで、インストールしていないものがあれば、インストールしましょう。
# !/usr/bin/python2.7
# module ----
import os
import webbrowser
from datetime import datetime, timedelta
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
import gdata.photos.service
import gdata.media
import gdata.geo
import httplib2
import json
import urllib2
# Google Authetication
def OAuth2Login(client_secrets, credential_store, email):
scope='https://picasaweb.google.com/data/'
user_agent='picasawebuploader'
storage = Storage(credential_store)
credentials = storage.get()
if credentials is None or credentials.invalid:
flow = flow_from_clientsecrets(client_secrets, scope=scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob')
uri = flow.step1_get_authorize_url()
webbrowser.open(uri)
code = raw_input('Enter the authentication code: ').strip()
credentials = flow.step2_exchange(code)
storage.put(credentials)
if (credentials.token_expiry - datetime.utcnow()) < timedelta(minutes=5):
http = httplib2.Http()
http = credentials.authorize(http)
credentials.refresh(http)
gd_client = gdata.photos.service.PhotosService(source=user_agent,
email=email,
additional_headers={'Authorization' : 'Bearer %s' % credentials.access_token})
return gd_client
# main -----
if __name__ == '__main__':
email = os.environ['EMAIL']
confDir = os.path.abspath(os.path.dirname(__file__))
client_secrets = os.path.join(confDir, 'photo-gallery.json')
credential_store = os.path.join(confDir, 'credentials.dat')
gd_client = OAuth2Login(client_secrets, credential_store, email)
albums = gd_client.GetUserFeed()
for album in albums.entry:
print 'Album: %s (%s)' % (album.title.text, album.numphotos.text)
photos = gd_client.GetFeed('/data/feed/api/user/default/albumid/%s?kind=photo' % (album.gphoto_id.text))
for photo in photos.entry:
print(photo.title.text)
f = open(photo.title.text, 'w')
f.write(urllib2.urlopen(photo.content.src).read())
f.close()
そして、上のファイルを実行してみると、
$ python google_photo_to_slack.py
下のように、ブラウザには、写真のページが表示され、コンソールには、ブラウザに表示されているauthentication codeを入力せよとのものが出てきます。
Enter the authentication code:
ブラウザに表示されるauthentication codeを入力すれば、ログイン完了です。
もう一度、
$ python google_photo_to_slack.py
を実行すれば、google photoにある写真が全て、ダウンロードされていると思います。
5. RtmbotとSlack APIを使って、Slackに文章と写真を投稿。
上のGooglePhotoToSlackファイルを下のように編集しましょう。
class GooglePhotoToSlackBot (Plugin):
MEDIA_ARR = []
RANDOM_NUMBER = 0
EMAIL = os.version['EMAIL']
CHANNEL_POST = ''
SLACK_BOT_TOKEN = os.version['SLACK_BOT_TOKEN']
PLUGIN_CHILD_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
PLUGIN_DIRECTORY = os.path.abspath(
os.path.join(PLUGIN_CHILD_DIRECTORY, os.pardir)
)
RTMBOT_DIRECTORY = os.path.abspath(
os.path.join(PLUGIN_DIRECTORY, os.pardir)
)
CLIENT_SECRETS = os.path.join(RTMBOT_DIRECTORY, os.version['SECRET_JSON'])
CREDENTIAL_STORE = os.path.join(
RTMBOT_DIRECTORY, os.version['CREDENTIAL_DAT']
)
def process_message(self, data):
feedback_pattern = re.compile(
# ここには、slack users list apiに表示されるUから始まるbotのidを入れてください
r'.*<@UAAAAAAA.*(gallery).*', re.DOTALL | re.IGNORECASE
)
if not (re.match(feedback_pattern, data['text'])):
return
self.CHANNEL_POST = data['channel']
message = u"本日の画像/映像をダウンロードしています!少しお待ち下さい! "
message += "動画の場合は、ダウンロードに時間がかかる場合があります。"
response = self.slack_client.api_call(
"chat.postMessage",
channel=self.CHANNEL_POST,
text=message,
link_names=1,
as_user=True
)
self.fetch_all_media()
self.post_random_media()
def oauth_login(self, client_secrets, credential_store, email):
scope = 'https://picasaweb.google.com/data/'
user_agent = 'picasawebuploader'
storage = Storage(credential_store)
credentials = storage.get()
now_time = datetime.utcnow()
if credentials is None or credentials.invalid:
flow = flow_from_clientsecrets(
client_secrets,
scope=scope,
redirect_uri='urn:ietf:wg:oauth:2.0:oob'
)
uri = flow.step1_get_authorize_url()
webbrowser.open(uri)
code = raw_input('Enter the authentication code: ').strip()
credentials = flow.step2_exchange(code)
storage.put(credentials)
if (credentials.token_expiry - now_time) < timedelta(minutes=5):
http = httplib2.Http()
http = credentials.authorize(http)
credentials.refresh(http)
gd_client = gdata.photos.service.PhotosService(
source=user_agent,
email=email,
additional_headers={
'Authorization': 'Bearer %s' % credentials.access_token
}
)
return gd_client
def fetch_all_media(self):
gd_client = self.oauth_login(
self.CLIENT_SECRETS,
self.CREDENTIAL_STORE,
self.EMAIL
)
albums = gd_client.GetUserFeed()
for album in albums.entry:
medias = gd_client.GetFeed(
'/data/feed/api/user/default/albumid/%s' %
(album.gphoto_id.text)
)
for media in medias.entry:
self.MEDIA_ARR.append(media)
def get_random_number_in_array(self, arr):
max_length = len(arr)
return random.randint(0, max_length)
def post_random_media(self):
self.RANDOM_NUMBER = self.get_random_number_in_array(self.MEDIA_ARR)
media_object = self.MEDIA_ARR[self.RANDOM_NUMBER]
media_file = open(media_object.title.text, 'wb')
media_file.write(response.content)
media_file.close()
media_path = self.RTMBOT_DIRECTORY + "/" + media_object.title.text
with open(media_path, 'rb') as f:
param = {
'token': self.SLACK_BOT_TOKEN,
'channels': self.CHANNEL_POST,
'title': u'Today\'s ' + media
}
r = requests.post(
"https://slack.com/api/files.upload",
params = param,
files = {'file': f}
)
そして、rtmbotディクレトリで、rtmbotコマンドを入力し、rtmbotサーバーを立ち上げます。
そのあと、スラックで、@galleryと入力しましょう。(どのチャンネルでも大丈夫です。)
$ rtmbot
上のコードにある本日の画像/映像をダウンロードしています!少しお待ち下さい!
と写真がスラックに流れれば、写真botの完了です!!
全コード
いろいろと機能(ダウンロードした写真を溜めないように、写真を削除するなど)を加えたものをgithubにあげたので、興味がある方はみていただけれると幸いです。
https://github.com/romukey/PythonAlgorithm/blob/master/google_gallery/plugins/google_photo_to_slack.py
参考にしたもの
Picasa Web API の Documentation
https://developers.google.com/picasa-web/docs/1.0/developers_guide_python
Google OAuthのLoginのやり方
https://stackoverflow.com/questions/30474269/using-google-picasa-api-with-python