透過 LINE 上傳圖片到 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 雲端硬碟喔~
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~