python google spreadsheet api

1. GCPのプロジェクト作成
2. Google Drive APIをONにする。
3. Google Sheets APIをONにする。

4. pipで必要なパッケージをインストールする。

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib oauth2client


5. app.pyコード

import os.path
from googleapiclient.discovery import build
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from googleapiclient.http import MediaFileUpload
import httplib2
import os

SCOPES = ['https://www.googleapis.com/auth/drive',
          'https://www.googleapis.com/auth/spreadsheets']
CRED_FILE = 'token.json'

def get_cred():
    creds = None

    if os.path.exists(CRED_FILE):
        creds = Storage(CRED_FILE).get()
        return creds
    
    if not creds or not creds.valid :
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = flow_from_clientsecrets(
                'credentials.json',
                scope=SCOPES,
                redirect_uri='urn:ietf:wg:oauth:2.0:oob')

            auth_uri = flow.step1_get_authorize_url()
            print(auth_uri)
            token = input("認証コードを入力してください。")
            creds = flow.step2_exchange(token)
            Storage(CRED_FILE).put(creds)
    return creds

def get_sheets(shreadsheet_id):
    creds = get_cred()
    service = build('sheets', 'v4', credentials=creds)
    result = service.spreadsheets().values().get(spreadsheetId=spreadsheet_id, range='A1:B5').execute()
    #print(result['range'])
    #print(result['values'])
    count = -1
    for col in result['values']:
        count+=1
        if count == 0:
            continue
        print(col)

def write_sheets(spreadsheet_id, values):
    creds = get_cred()
    service = build('sheets', 'v4', credentials=creds)
    body = {'values':values}
    service.spreadsheets().values().update(
        spreadsheetId=spreadsheet_id,
        range='C1:D5',
        valueInputOption="USER_ENTERED",
        body=body
    ).execute()

認証はdriveの時と同じ。
get_sheetsで得られる情報は空の二重リスト。
また、書き込みを行うときは二重リストで渡す。

6. 実行用コード(読み込み)

get_sheets({シートのid})

7. 実行用コード(書き込み)

values = [['id', 'name'], ['1', 'apple'], ['2', 'banana'], ['3', 'cherry'], ['4', 'durian']]
write_sheets({シートのid}, values)

Google Drive API python

1. GCPへログイン
2. Google Drive APIを有効化
3. Oauth Client IDを作成
4. jsonをダウンロード


pipで必要なパッケージをインストール

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib oauth2client

app.py
コード全体

import os.path
from googleapiclient.discovery import build
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from googleapiclient.http import MediaFileUpload
import httplib2
import os

SCOPES = ['https://www.googleapis.com/auth/drive']
CRED_FILE = 'token.json'

def get_cred():
    creds = None

    if os.path.exists(CRED_FILE):
        creds = Storage(CRED_FILE).get()
        return creds
    
    if not creds or not creds.valid :
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = flow_from_clientsecrets(
                'credentials.json',
                scope=SCOPES,
                redirect_uri='urn:ietf:wg:oauth:2.0:oob')

            auth_uri = flow.step1_get_authorize_url()
            print(auth_uri)
            token = input("認証コードを入力してください。")
            creds = flow.step2_exchange(token)
            Storage(CRED_FILE).put(creds)
    return creds

def create_folder(folder_name, parent_id):
    creds = get_cred()
    drive_service = build('drive', 'v3', http=creds.authorize(httplib2.Http()))
    file_metadata = {
        'name':folder_name,
        'mimeType':'application/vnd.google-apps.folder',
        'parents':[parent_id]
    }
    dict_data = drive_service.files().create(body=file_metadata, fields='id').execute()
    return dict_data['id']


def upload_file(file_name, folder_id, mimetype):
    creds = get_cred()
    drive_service = build('drive', 'v3', http=creds.authorize(httplib2.Http()))
    file_metadata = {
        'name': file_name,
        'mimetype':mimetype,
        'parents':[folder_id]
    }

    media = MediaFileUpload(
        file_name,
        mimetype=mimetype,
        resumable=True
    )
    file=drive_service.files().create(
        body=file_metadata, media_body=media, fields='id'
    ).execute()

別途credentials.jsonをapp.pyと同じ階層に配置する必要がある。
認証部分のみ少し複雑なので説明する。

SCOPES = ['https://www.googleapis.com/auth/drive']
CRED_FILE = 'token.json'

def get_cred():
    creds = None

    if os.path.exists(CRED_FILE):
        creds = Storage(CRED_FILE).get()
        return creds
    
    if not creds or not creds.valid :
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = flow_from_clientsecrets(
                'credentials.json',
                scope=SCOPES,
                redirect_uri='urn:ietf:wg:oauth:2.0:oob')

            auth_uri = flow.step1_get_authorize_url()
            print(auth_uri)
            token = input("認証コードを入力してください。")
            creds = flow.step2_exchange(token)
            Storage(CRED_FILE).put(creds)
    return creds

最初のif文は前回の認証tokenが残っていれば認証いけるようにする。(直す余地ありそう。)
次のif文ではcredentialsを作成する。
flow.step1_get_authorize_url()で認証用ページのurlを取得
urlを表示してアクセスするようにしている。
tokenが発行されたらそれをcredentials情報に変換して返す。

GCPのPostgresqlにDocker-psqlで接続する。

まずはpsqlの準備。
イメージはcentosを使用。

docker pull centos

testcという名前でコンテナを起動。

docker run -itd --name testc centos

コンテナの中に入る。

docker exec -it testc /bin/bash

psqlyumで取得する。
一応updateをかけてから。
応答は全部y(yes)でOK。

yum update

psqlを取得する。

yum install postgresql

psqlのバージョンを確認する。
バージョン以下のものをGCPの方で作成する。

psql --version

次にGCPの方でPostgresqlの準備。

決めることとして

  • インスタンスid(任意)
  • パスワード
  • データベースのバージョン(psql以下のバージョンにしておく)
  • リージョン(シングル&東京)
  • マシンタイプ軽量
  • 接続。パブリックIPでネットワークに自分の場所のIPを追加。(CIDRを/32にしておく。)

これで作成を行う。
DBインスタンスの作成が完了したらpsqlで接続をする。

psql -h {IPアドレス} -p 5432 -U postgres -d postgres

その時、パスワードを聞かれるが上記で作成したパスワードを打つ。
接続できれば成功。
psqlを終了するときは\qで終了する。

Fastlyが落ちた件 感想

いつかFastly触ってみたいけど、DNS云々はすぐできないので今回は触らない。

業務終了間際、Slackにエラー通知が鳴った。 まれにエラー自体は起こるのであまり気にしてなかったがすぐにまたエラー通知が鳴る。 さすがにまずいと思いインフラを調べた。普通にAPI情報取得部分で取れなくなっていた。 ともすれば、原因はAPI配信側だ。ただ、エンジニアとしてあらゆる可能性を想定しなくてはいけないから一応色々と調べた。 調べつつ他のSlackを見てみると、他のサイトもおかしくなっているらしい。ともすれば原因はAWSか? twitterをみると、AWS障害か?のような記述が確かにある。 しかし社内の出来るエンジニアがFastlyが障害になっているということを発見してくれた。

Fastly Status

上記のページで障害が発生していることが分かったらしい。こういう時にstatusページを見にいくようにしなければならないと反省。 FastlyというのはCDNサービスのようだが何をやっているかというと

  • 画像配信(キャッシュによって読み込みを早くする)
  • 動画配信
  • セキュリティ
  • トラフィック分散

ということをやっているらしい。

Fastly

わりと色々な企業で使われていたらしく、様々な場所で障害が発生したらしい。 例えば、利用用途として画像配信のみを使っていた場合は画像が上手く読み込めなくなったり トラフィック分散として使っていた場合はシステムがエラーでストップしてしまう、なども起こっただろう。

なぜこのような大規模障害が起こってしまったのか原因はわからないが、ここまで大規模だと何かしらの設定ミスなどで起こってしまったのかもしれない。批判したいわけではないが、原因は気になる所である。

一応今回の障害は1時間程度で復旧した。

python開発環境をDockerで環境構築する

今回はDockerを使ってpythonの開発環境を構築する。
まずファイル構成は以下の通りにする。

f:id:ymtech0615:20210608014733p:plain
ファイル構成

app.py

print('HelloWorld')


とりあえずHelloWorldを表示するもの。

Dockerfile

FROM python:3.9-slim

ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

python3.9slimイメージを使う。ここは基本最新を使っていけばよい。
基本的にはslimイメージで問題ないが、システムの関係でjavaを入れたいなっていう時にslimだと困ったので時と場合によっては別のもの使うべし。
copyによってdocker imageの中にローカルコードを全部コピーしている。

2つのファイルを配置したら以下のコマンドでdocker imageを作成する。

docker build -t test .

上記コマンドによってdocker imageを作成する。
tオプションはイメージの名前をつける。
最後見えづらいが.を指定してカレントディレクトリにあるDockerfileを使ってimageを作成する。

コンテナを起動

docker run -itd --name testc -v $PWD:/app test

上記コマンドによってdocker imageからdocker containerを作成する。
itはこの後docker container内で色々やるのに必要。
dオプションはバッググラウンド起動。
nameオプションはコンテナの名前をつける。
vオプションはコンテナと現在のディレクトリをつなげる。$PWDはカレントディレクトリの絶対パスなので{docker起動側}:{docker container内}で繋げる。
最後に起動したいイメージの名前をつける。

コンテナの中に入る。

docker exec -it testc /bin/bash

pythonが実行できるか確認

python app.py

HelloWorldが表示されたら成功。
この状態で別の文字列に書き換えると変更が反映されている。
vオプションが無いと、書き換えても変更が反映されない。

開発が終わったら、コンテナから出る

exit

コンテナを止める

docker stop testc

コンテナを削除

docker rm testc

イメージを削除

docker image rm test

APEX アリーナ

コスト

武器コスト

武器名 コスト
p2020 0
モザンピーク 0
EVA-8オート 250
RE-45-オート 250
オルタネーターSMG 400
ピースキーパー 500
マスティフ 500
ボルトSMG 500
ウイングマン 500
R-99 SMG 550
ハボックライフル 350
LスターLMG 400
ディボーションLMG 450
ヘムロックバーストAR 500
VK-47フラットライン 550
M600スピットファイア 600
R-301カービン 600
G7スカウト 350
30-30リピーター 350
ロングボウDMR 400
センチネル 400
ボセックコンバウンドボウ 600
チャージライフル 700

消耗品コスト

  • 投げ物は合計で3つまで
消耗品名 コスト
注射器 25 8
医療キット 50 4
シールドセル 75 8
シールドバッテリー 150 4
バックパック 250 1
フラググレネード 75 3
テルミットグレネード 100 3
アークスター 100 3

戦術スキル

キャラ名 コスト
ブラッドハウンド 150 3(1)
ライフライン 50 3(1)
ジブラルタル 200 5(1)
パスファインダー 50 7(3)
レイス 50 4(1)
バンガロール 50 5(2)
コースティック 50 6(3)
ミラージュ 50 7(3)
レブナント 50 6(2)
オクタン 50 7(3)
ワットソン 50 9(5)
クリプト 100 3(1)
ローバ 50 5(2)
ランパート 50 9(3)
ホライゾン 100 4(2)
ヒューズ 150 6(2)
ヴァルキリー 200 3(1)

アルティメット

キャラ名 コスト 制限
ブラッドハウンド 350 1
ライフライン 400 0
ジブラルタル 500 2
パスファインダー 150 0
レイス 150 0
バンガロール 500 2
コースティック 400 2
ミラージュ 350 0
レブナント 600 2
オクタン 300 0
ワットソン 200 0
クリプト 600 2
ローバ 200 0
ランパート 300 2
ホライゾン 400 2
ヒューズ 400 1
ヴァルキリー 150 1

マップ

オアシス

f:id:ymtech0615:20210515163744p:plain
オアシス

砲台

f:id:ymtech0615:20210515163815p:plain
砲台

フェーズゲート

f:id:ymtech0615:20210517013331p:plain
フェーズゲート