Google drive 公開設定

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のメッセージ送信と組み合わせる

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です