以前仕事で、SpreadSheetでQRコードを管理したいという要望があったのだが、SpreadSheetに画像ってどうやってアップロードするんだ?GASでやればいいのか?わからん!とかいろいろ悩んでいるうちに我を忘れて、SpreadSheetを方眼にしてそこにQRコードをプロットするという、明日から使える無駄技術を身につけてしまったのでここに書いておく。
#SpreadSheetを外部から操作するための準備
SpreadSheetをgspreadで操作するためにはGoogleCloudのコンソールからAPIを有効にして、jsonキーをダウンロードしないといけない。ここが一番めんどくさかった。
以下が参考になります。
[参考]
【もう迷わない】Pythonでスプレッドシートに読み書きする初期設定まとめ
pythonでGoogle Spread Sheetをいじる(OAuth)
#QRのデータなんてどうせどっかに二次元配列でおいてるだろ
ってことでpythonのqrcodeモジュールのコードサンプルを見てみた。使い方は要約すると以下のような感じ。
import qrcode
img = qrcode.make('hogehoge')
img.save('qrcode.png')
なかった。。。
まぁそんな使い方する人はいないので、考えてみれば当たり前である。
#qrcodeモジュールの中身を見てみる
いやいや内部的にはどっかにあるでしょ!
というわけでqrcodeモジュールの中身を見てみる。
import inspect
import qrcode
print(inspect.getfile(qrcode))
たったこれだけのコードでモジュールの__init__.py
の場所がわかるので、そこから探すとよいです。
該当のmain.pyの中身を見てみると、どうやらQRCode().modules
に二次元配列でそれっぽいものが入っているので、これを使うことにした。
>>> import qrcode
>>> qr = qrcode.QRCode()
>>> qr.add_data('hoge')
>>> qr.make()
>>> qr.modules
[[True, True, True, True, True, True, True, False, False, True, False, False, False, False, True, True, True, True, True, True, True], [True, False, False, False, False, False, True, False, False, True, False, True, False, False, True, False, False, False, False, False, True], [True, False, True, True, True, False, True, False, True, True, False, True, False, False, True, False, True, True, True, False, True], [True, False, True, True, True, False, True, False, True, True, True, True, False, False, True, False, True, True, True, False, True], [True, False, True, True, True, False, True, False, True, True, False, True, True, False, True, False, True, True, True, False, True], [True, False, False, False, False, False, True, False, True, True, False, False, True, False, True, False, False, False, False, False, True], [True, True, True, True, True, True, True, False, True, False, True, False, True, False, True, True, True, True, True, True, True], [False, False, False, False, False, False, False, False, True, False, False, True, True, False, False, False, False, False, False, False, False], [True, False, True, True, True, True, True, False, False, True, False, False, True, False, True, True, True, True, True, False, False], [True, False, False, False, True, True, False, False, False, False, True, False, True, False, False, True, False, True, False, False, True], [True, True, True, False, False, True, True, False, False, True, False, True, False, True, False, False, True, True, False, True, False], [False, False, False, True, False, False, False, True, True, True, True, False, False, False, False, True, True, True, True, False, False], [False, True, True, True, True, True, True, True, True, False, False, True, False, True, False, False, True, False, False, False, True], [False, False, False, False, False, False, False, False, True, False, True, True, True, True, True, False, False, True, True, False, True], [True, True, True, True, True, True, True, False, False, False, False, False, True, False, True, True, False, True, False, True, False], [True, False, False, False, False, False, True, False, True, True, False, True, True, True, True, False, False, True, True, False, False], [True, False, True, True, True, False, True, False, True, True, True, False, True, False, False, True, False, False, False, True, False], [True, False, True, True, True, False, True, False, True, True, False, False, True, False, False, True, False, True, True, False, False], [True, False, True, True, True, False, True, False, True, False, True, True, False, True, False, False, True, True, True, False, False], [True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, True, True, False, True, False, False], [True, True, True, True, True, True, True, False, True, True, False, True, False, True, False, False, True, False, True, True, False]]
あった!
#ソースコード
import qrcode
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from gspread_formatting import *
import time
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('XXXXXXXXXXXXXXXXXXXXXXX.json', scope)
gc = gspread.authorize(credentials)
SPREADSHEET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
workbook = gc.open_by_key(SPREADSHEET_KEY)
text = input("Please input =>")
qr = qrcode.QRCode()
qr.add_data(text)
qr.make()
body = {
"requests": [
{
"updateDimensionProperties": {
"range": {
"dimension": "COLUMNS",
"startIndex": 1,
"endIndex": len(qr.modules)+1
},
"properties": {
"pixelSize": 25
},
"fields": "pixelSize"
}
}
]
}
res = workbook.batch_update(body)
body = {
"requests": [
{
"updateDimensionProperties": {
"range": {
"dimension": "ROWS",
"startIndex": 1,
"endIndex": len(qr.modules)+1
},
"properties": {
"pixelSize": 25
},
"fields": "pixelSize"
}
}
]
}
res = workbook.batch_update(body)
fmt = cellFormat(
backgroundColor=color(255, 255, 255)
)
for ii, l in enumerate(qr.modules):
for jj, b in enumerate(l):
if b:
format_cell_range(workbook.sheet1, f'{chr(65+ii+1)}{jj+2}', fmt)
time.sleep(0.2)
img = qr.make_image()
img.save('qr_image.png')
今回gspread_formatting
というモジュールを使ったが、少し癖が強かった。
セルの指定が"A1"の形式でしかできない(?)ようなので、chr()
で無理やり変換している。よって"AA"以降の列には対応していないので、長い文字列だとQRコードの右側が切れる。
また、もう少しまとめて一度に書きこめればいいのだが、現状1セルずつ塗っているので処理がめちゃ遅い。
sleepを0.2入れてるのは、普通に回すと以下のGoogle Sheets APIの規約に引っかかるため。
This version of the Google Sheets API has a limit of 500 requests per 100 seconds per project, and 100 requests per 100 seconds per user.
こちらが実行中の動画。
10倍速でもこの速度である。
Hello world!はダサいのでHello hello, how low?(かっこいい)を合成している。
QRコードをspread sheetで管理したいという声に応えて、spread sheetにQRコードをプロットしてみました。
— たくみ@スカジャンのエンジニア (@hatt_takumi) March 7, 2020
明日使える無駄技術をあなたに。
こちらも近々Qiitaに投稿予定。
ちなみに動画は10倍速笑笑#Python#駆け出しエンジニアと繋がりたい#エンジニアと繋がりたい#無駄な技術 pic.twitter.com/wDFjIT7eWo