Google drive 公開設定
from googleapiclient.discovery import build
from google.oauth2 import service_account
# 認証情報のセットアップ(Google Drive API 用のサービスアカウント)
SCOPES = ["https://www.googleapis.com/auth/drive.metadata.readonly"]
SERVICE_ACCOUNT_FILE = "service_account.json"
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
service = build("drive", "v3", credentials=creds)
# 共有されているフォルダを検索
query = "mimeType='application/vnd.google-apps.folder' and sharedWithMe"
results = service.files().list(q=query, fields="files(id, name, owners, webViewLink)").execute()
folders = results.get("files", [])
if not folders:
print("公開されているフォルダはありません。")
else:
for folder in folders:
print(f"フォルダ名: {folder['name']}, URL: {folder['webViewLink']}, 所有者: {folder['owners'][0]['emailAddress']}")
の結果からいくつか気になったのでGPTで確認
となったが
✅ Google Drive フォルダの webViewLink が表示されるなら公開URLになっているのか?
結論:まだ「完全な公開URL」にはなっていません! 🚨
* webViewLink は 「Google Drive 上でフォルダを閲覧できるURL」 であり、
誰でも直接アクセスできる公開URLではない 可能性があります。
* LINE Bot で画像を表示するには「画像自体のURL」が必要 であり、フォルダの webViewLink ではなく、画像ファイルごとのURLを取得する必要がある。
とのこと
🚀 1. webViewLink とは?
* webViewLink のURL(例: https://drive.google.com/drive/folders/…)は、Google Drive 上のフォルダを開くためのもの。
* これは「フォルダの中身をブラウザで表示する」ためのURLであり、LINE API で画像を表示するための直接URLではない。
✅ 公開されているフォルダなら、自分のアカウントでアクセス可能 ❌ ただし、画像を埋め込むには、個々の画像の公開URLが必要
本当にフォルダ内の画像が公開されているか確認
フォルダが「共有」されているだけでは、フォルダ内のファイルが「完全公開」されているとは限りません。
各画像の permissions を確認することで、画像が一般公開されているかどうかをチェック
python folder_access.py
from googleapiclient.discovery import build
from google.oauth2 import service_account
# Google Drive API 認証設定
SCOPES = ["https://www.googleapis.com/auth/drive"]
SERVICE_ACCOUNT_FILE = "service_account.json"
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
drive_service = build("drive", "v3", credentials=creds)
# 共有フォルダ ID
FOLDER_ID = ""
def check_image_permissions():
"""フォルダ内の画像が公開されているかチェック"""
query = f"'{FOLDER_ID}' in parents and mimeType contains 'image/' and trashed=false"
results = drive_service.files().list(q=query, fields="files(id, name, permissions, webViewLink)").execute()
files = results.get("files", [])
if not files:
print("フォルダ内に画像がありません。")
return
for file in files:
file_id = file["id"]
file_name = file["name"]
webViewLink = file.get("webViewLink", "なし")
# ファイルの公開設定を確認
permissions = drive_service.permissions().list(fileId=file_id).execute()
public_access = any(p["type"] == "anyone" for p in permissions.get("permissions", []))
if public_access:
print(f"✅ 画像: {file_name} は公開されています。URL: {webViewLink}")
else:
print(f"❌ 画像: {file_name} は非公開です。URL: {webViewLink} (アクセス不可)")
# 画像の公開設定を確認
check_image_permissions()
結果は
❌ 画像: PXL_20240617_182349485.jpg は非公開です。URL: https://drive.google.com/file/ (アクセス不可)
となるので
完全公開になっていないため画像が取得できていなかった
✅ 問題点
LINE の originalContentUrl / previewImageUrl に Google Drive の
「uc?id=…」形式のURL を指定しているため、画像が正しく表示されない可能性がある。
Google Drive の 「uc?id=…」形式のURLは、一部の環境では直接開けないことがある(プレビュー画面になってしまう)。
このためコードの変更
def get_drive_image_url(file_id):
return f"https://drive.google.com/uc?id={file_id}"
から
修正後(公開URLを取得するコードに変更)
def get_drive_image_url(file_id):
"""Google Drive のファイルIDを公開URLに変換する"""
try:
# ファイルのアクセス権限を「公開」に設定
drive_service.permissions().create(
fileId=file_id,
body={"role": "reader", "type": "anyone"},
).execute()
# 画像のダウンロードURLを取得
return f"https://drive.google.com/thumbnail?id={file_id}&sz=w1000"
except Exception as e:
print(f"Error making image public: {e}")
return None
これで全体コードは
import requests
import random
import time
from googleapiclient.discovery import build
from google.oauth2 import service_account
# ① Google Drive API の設定
SCOPES = ["https://www.googleapis.com/auth/drive"]
SERVICE_ACCOUNT_FILE = "service_account.json"
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive_service = build("drive", "v3", credentials=creds)
# ② 送信先の LINE API 設定
LINE_PUSH_URL = "https://api.line.me/v2/bot/message/push"
LINE_CHANNEL_ACCESS_TOKEN = ""
USER_ID = "USER_LINE_ID"
# ③ Google Drive の「temp」フォルダID
FOLDER_ID = ""
def get_drive_images():
"""
Google Drive の temp フォルダ内の画像リストを取得し、画像の `id` をリストで返す
"""
query = f"'{FOLDER_ID}' in parents and mimeType contains 'image/' and trashed=false"
results = drive_service.files().list(q=query, fields="files(id, name)").execute()
files = results.get("files", [])
if not files:
print("No images found in the Drive folder.")
return None
return [file["id"] for file in files]
def get_drive_image_url(file_id):
"""
Google Drive のファイルIDを公開URLに変換する
"""
try:
# ファイルのアクセス権限を「公開」に設定
drive_service.permissions().create(
fileId=file_id,
body={"role": "reader", "type": "anyone"},
).execute()
# 画像のダウンロードURLを取得
return f"https://drive.google.com/thumbnail?id={file_id}&sz=w1000"
except Exception as e:
print(f"Error making image public: {e}")
return None
def send_image(image_url):
"""
LINE API を使い、取得した画像URLを LINE ユーザーに送信する
"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {LINE_CHANNEL_ACCESS_TOKEN}"
}
payload = {
"to": USER_ID,
"messages": [
{
"type": "image",
"originalContentUrl": image_url,
"previewImageUrl": image_url
}
]
}
response = requests.post(LINE_PUSH_URL, headers=headers, json=payload)
print(response.status_code, response.text)
def main():
"""
画像リストを取得し、ランダムな画像を選んでLINEに送信
"""
image_ids = get_drive_images()
if not image_ids:
print("No images found, skipping LINE push.")
return
# 画像をランダムに選択
random_image_id = random.choice(image_ids)
image_url = get_drive_image_url(random_image_id)
if image_url:
# LINE に画像を送信
send_image(image_url)
else:
print("Failed to get a valid image URL.")
# スケジュール実行(30分ごと)
if __name__ == "__main__":
while True:
main()
time.sleep(1800) # 30分ごとに実行
として再度実行すると
400 {"message":"The property, 'to', in the request body is invalid (line: -, column: -)"}
よくみたらユーザIDを設定忘れていた…
import requests
import random
import time
from googleapiclient.discovery import build
from google.oauth2 import service_account
# ① Google Drive API の設定
SCOPES = ["https://www.googleapis.com/auth/drive"]
SERVICE_ACCOUNT_FILE = "service_account.json"
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive_service = build("drive", "v3", credentials=creds)
# ② 送信先の LINE API 設定
LINE_PUSH_URL = "https://api.line.me/v2/bot/message/push"
LINE_CHANNEL_ACCESS_TOKEN = ""
USER_ID = ""
# ③ Google Drive の「temp」フォルダID
FOLDER_ID = ""
def get_drive_images():
"""
Google Drive の temp フォルダ内の画像リストを取得し、画像の `id` をリストで返す
"""
query = f"'{FOLDER_ID}' in parents and mimeType contains 'image/' and trashed=false"
results = drive_service.files().list(q=query, fields="files(id, name)").execute()
files = results.get("files", [])
if not files:
print("No images found in the Drive folder.")
return None
return [file["id"] for file in files]
def get_drive_image_url(file_id):
"""
Google Drive のファイルIDを公開URLに変換する
"""
try:
# ファイルのアクセス権限を「公開」に設定
drive_service.permissions().create(
fileId=file_id,
body={"role": "reader", "type": "anyone"},
).execute()
# 画像のダウンロードURLを取得
return f"https://drive.google.com/thumbnail?id={file_id}&sz=w1000"
except Exception as e:
print(f"Error making image public: {e}")
return None
def send_image(image_url):
"""
LINE API を使い、取得した画像URLを LINE ユーザーに送信する
"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {LINE_CHANNEL_ACCESS_TOKEN}"
}
payload = {
"to": USER_ID,
"messages": [
{
"type": "image",
"originalContentUrl": image_url,
"previewImageUrl": image_url
}
]
}
response = requests.post(LINE_PUSH_URL, headers=headers, json=payload)
print(response.status_code, response.text)
def main():
"""
画像リストを取得し、ランダムな画像を選んでLINEに送信
"""
image_ids = get_drive_images()
if not image_ids:
print("No images found, skipping LINE push.")
return
# 画像をランダムに選択
random_image_id = random.choice(image_ids)
image_url = get_drive_image_url(random_image_id)
if image_url:
# LINE に画像を送信
send_image(image_url)
else:
print("Failed to get a valid image URL.")
# スケジュール実行(30分ごと)
if __name__ == "__main__":
while True:
main()
time.sleep(1800) # 30分ごとに実行
で実行すると問題なく画像が表示される
次はこれをモジュールにしてLINEのメッセージ送信と組み合わせる



