串接 Google 云端硬盘
在“储存用户传送的图片或影片”教学里,有介绍将用户图片储存在本机环境的做法,这篇教学将会更近一步,把用户上传的图片,储存到 Google 云端硬盘。
快速导览:
设定 Google Cloud 与 Google Drive
参考“上传文件到 Google 云端硬盘 ( Google Drive )”的范例程序,启用 Google Cloud 里的 Google Drive API。
建立并下载金钥 JSON 文件。
打开 Google 云端硬盘要上传文件的文件夹共用权限,将权限设定为“编辑者”,前置动作就准备完成。
上传图片 ( 本机环境、Colab )
参考“建立并串接 Webhook”教学,在本机环境或 Colab 启动服务器,并串连 ngrok 产生 ngrok 网址,接着使用下方程序码 ( Colab 请参考注解打开需要的区块 ),就能在接收用户上传的图片后,将图片转换成二进制编码,透过 MediaIoBaseUpload 建立对象后,就能上传到 Google 云端硬盘。
Google Drive API 金钥 JSON 文件,需要存放在和执行的 python“相同目录”,使用 Colab 请额外注意路径。
from flask import Flask, request
# from pyngrok import ngrok # Colab 環境需要,本機環境不需要
import json, io
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, StickerSendMessage, ImageSendMessage, LocationSendMessage
app = Flask(__name__)
# Colab 環境需要下面這三行,本機環境不需要
# port = "5000"
# public_url = ngrok.connect(port).public_url
# print(f" * ngrok tunnel \"{public_url}\" -> \"http://127.0.0.1:{port}\" ")
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseUpload
UPLOAD_FOLDER = '你共用的資料夾 ID'
SCOPES = ['https://www.googleapis.com/auth/drive']
# path = '/content/drive/MyDrive/Colab Notebooks/' # Colab 換路徑使用,本機環境不需要
SERVICE_ACCOUNT_FILE = '金鑰檔案名稱與路徑'
# 建立憑證物件
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('drive', 'v3', credentials=creds)
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = '你的 Access Token'
secret = '你的 Channel Secret'
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
type = json_data['events'][0]['message']['type'] # 取得 LINE 收到的訊息類型
print(type)
# 判斷如果是文字
if type=='text':
msg = json_data['events'][0]['message']['text'] # 取得 LINE 收到的文字訊息
reply = msg
# 判斷如果是圖片
elif type == 'image':
msgID = json_data['events'][0]['message']['id'] # 取得訊息 id
message_content = line_bot_api.get_message_content(msgID) # 根據訊息 ID 取得訊息內容
filename = f'{msgID}.jpg' # 上傳檔的名字
imageBytes = io.BytesIO(message_content.content) # 將 jpg 轉換成二進位
media = MediaIoBaseUpload(imageBytes, mimetype='image/jpg', resumable=True) # 建立上傳圖片物件
file = {'name': filename, 'parents': [UPLOAD_FOLDER]}
print("正在上傳檔案...")
file_id = service.files().create(body=file, media_body=media).execute() # 上傳圖片
print('雲端檔案ID:' + str(file_id['id']))
reply = '上傳成功!\n\n查看:https://drive.google.com/drive/folders/XXXXXXXXXXXXXXXX'
else:
reply = '你傳的不是文字或圖片呦~'
line_bot_api.reply_message(tk,TextSendMessage(reply)) # 回傳訊息
except Exception as e:
print('error')
print(e)
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
app.run()
完成后执行程序 ( 记得先使用 ngrok 产生 webhook 网址并提交至 LINE Developer ),传送图片到 LINE BOT,上传成功后就会出现上传消息以及 Google 云端硬盘网址。
前往 Google 云端硬盘也会看见上传的图片。
上传图片 ( Cloud Functions )
如果是使用 Cloud Functions,需要手动添加金钥 JSON 文件,无法使用上传功能。
同时也需要修改 requirements.txt 内容,加入 google 和 google-api-python-client 两个模组。
接着在 main.py 里使用下方的程序码,填入自己的云端硬盘 ID、金钥 JSON 档名、LINE Access Token 和 Channel Secret。
import functions_framework
from flask import Flask, request
import json, time, requests, math, io
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, StickerSendMessage, ImageSendMessage, LocationSendMessage
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseUpload
def googleDrive(fileName, fileContent):
try:
# 串接 Google 雲端硬碟
UPLOAD_FOLDER = '你共享的資料夾 ID'
SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = '金鑰檔案'
# 建立憑證物件
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('drive', 'v3', credentials=creds)
imageBytes = io.BytesIO(fileContent) # 轉換成二進位
media = MediaIoBaseUpload(imageBytes, mimetype='image/jpg', resumable=True) # 建立上傳物件
file = {'name': fileName, 'parents': [UPLOAD_FOLDER]}
file_id = service.files().create(body=file, media_body=media).execute() # 上傳檔案
reply = '上傳成功!\n\n查看:https://drive.google.com/drive/folders/XXXXXXXXXXXXXXXX'
except Exception as e:
print(e)
reply = '上傳失敗...'
return reply
@functions_framework.http
def linebot(request):
access_token = '你的 Access Token'
channel_secret = '你的 Channel Secret'
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(channel_secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
json_data = json.loads(body) # 轉換內容為 json 格式
reply_token = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token ( reply message 使用 )
user_id = json_data['events'][0]['source']['userId'] # 取得使用者 ID ( push message 使用 )
print(json_data) # 印出內容
type = json_data['events'][0]['message']['type']
if type == 'image':
line_bot_api.push_message(user_id, TextSendMessage(text='圖片上傳中....'))
msgID = json_data['events'][0]['message']['id'] # 取得訊息 ID
message_content = line_bot_api.get_message_content(msgID) # 取得上傳內容
fileName = f'{msgID}.jpg' # 使用訊息 ID 作為檔名
reply = googleDrive(fileName, message_content.content) # 執行上傳程式
text_message = TextSendMessage(text=reply)
line_bot_api.reply_message(reply_token,text_message)
else:
text_message = TextSendMessage(text='不知道你傳的是什麼...')
line_bot_api.reply_message(reply_token,text_message)
except Exception as e:
print(e)
return 'OK'
部署完成后,复制 Webhook 网址,就能回到 LINE Developer 里填入到 webhook 字段。
回到 LINE BOT 聊天视窗传送图片到,上传成功后就会出现上传消息以及 Google 云端硬盘网址。
前往 Google 云端硬盘也会看见上传的图片。
小结
透过 LINE BOT 传送图片到 Google 云端硬盘是很方便的一件事,但如果公开的服务,仍然要注意安全性的问题,避免有心人士滥用 Google 云端硬盘喔~
微信扫码关注
抖音扫码关注