Упростить обмен файлами
Простой обмен файлами
Пример кода для работы с общими папками Google Drive в совместных проектах
Недавно снова возникла проблема с обменом данными, и я подумал, что сейчас самое время разработать метод для работы с общими папками. Я работаю независимым профессионалом в области геоинформационных наук и часто взаимодействую с различными организациями одновременно. В своих проектах я заметил, что каждая организация имеет свой уникальный подход к работе с данными, определяемый своей культурой и рабочей этикой, что приводит к разнообразию методологий. К счастью, у них есть некоторые общие практики, и одна из них – работа с облачной системой управления данными, часто Google, но также может быть One-Drive (от Microsoft) или Dropbox.
В этой статье я объясню, как использовать Python с общими папками в экосистеме Google.

Практическое применение
Управление файлами на локальной машине – это очень индивидуально и (надеюсь) стандартизовано, или по крайней мере имеет некоторую стандартизацию, когда вы работаете в организации. Обмен файлами между системами может быть сложным, но работа с общими папками – это вариант, когда у вас нет прямого доступа к рабочей папке, и организация может предоставить вам специально назначенную рабочую папку для обмена файлами. В этом примере организация предоставила доступ к папке с названием DATA в их хранилище Google Drive, и договорились, что мы можем использовать эту папку для обмена файлами.
Управление локальными файлами
Для объяснения быстро, для тех, кто не знаком с обменом файлами в Google Drive, процесс начинается с получения электронного письма с приглашением внести свой вклад в конкретную папку; см. приглашение (слева) ниже. В приглашении есть кнопка, которая открывает веб-браузер с интерфейсом Google Drive (справа), связанным с Google-почтой получателя приглашения.
- Искусственный интеллект Chatbots создают программное обеспечение за несколько минут за менее чем $1
- Растущая жажда ИИ может вызвать глобальный дефицит воды
- 15 проектов, использующих искусственный интеллект для достижения Глобальных целей ООН

В интерфейсе есть несколько важных сведений, и знание их заранее поможет вам в дальнейшем процессе.
- В URL (вверху экрана) есть зашифрованный идентификатор, который Google использует для отслеживания всех операций с этой папкой, и этот идентификатор мы получим в коде Python позже в этой статье.
- Затем говорится: “Совместное использование со мной” и название общей папки; это также важно, потому что, когда мы монтируем Google Drive в блокноте CoLab, мы увидим, что эта категория недоступна.
- И, наконец, мы видим файлы и папки в папке Data; это означает, что мы можем получить доступ к нужной информации и добавлять новые файлы в папку. Однако могут возникнуть проблемы с настройками безопасности папки, поэтому хорошим тестом на этом этапе является создание небольшого текстового файла и перетаскивание его в папку “ExternalData”, чтобы проверить, что у вас есть полный доступ.
Чтобы сделать папку “Совместное использование со мной” доступной, нам нужно связать эту папку с локальным/личным диском. Мы можем сделать это, создав ярлык, но это ручной шаг и будет отличаться для каждого. Чтобы получить доступ к общей папке или файлу в Google Colab:
- Перейдите в раздел “Совместное использование со мной” в Google Drive.
- Выберите папку или файл, к которому вы хотите получить доступ.
- Щелкните правой кнопкой мыши на нем и выберите “Добавить ярлык к диску”, и появится всплывающее окно “Выбрать Мой Диск”, затем нажмите “Добавить ярлык”.
- Разместите ярлык в месте на вашем диске, где вы сможете его легко найти; в используемой мной настройке местоположение для ярлыков – “__Shared”, чтобы папка с ярлыками была вверху списка папок в разделе “Мой Диск”, а затем подкаталог для организации.
- Переименуйте ярлык в осмысленное имя; в этом примере я использую “DataDevelopement”. Местоположение файла и соглашения о его названии очень индивидуальны, и для работы программы не имеет значения, где файлы хранятся и как они называются, но наличие некоторой структуры может избежать некоторых проблем в дальнейшем.

С организованной локальной файловой системой и настроенным личным Google Drive, мы можем попытаться работать с этой общей папкой в блокноте Python и автоматизировать обмен файлами в проекте.
Установка
Этот проект основан на блокноте Google Colab или “Collaboratory”, который я поделюсь в конце этой статьи. Преимущество использования этой среды заключается в том, что она позволяет вам писать и выполнять код Python в браузере со следующими преимуществами:
- Отсутствие необходимости в настройке
- Бесплатный доступ к графическим процессорам
- Простое совместное использование
Это очень важные моменты при работе с организациями, у которых есть свои внутренние процедуры, потому что, как внешний сотрудник, у вас часто нет прямого доступа к кодовой базе (и это может иметь множество причин, от вопросов безопасности до ограничений управления проектом). Блокнот Colab является частью экосистемы Google и (как дополнительное преимущество) создает среду выполнения с возможностью подключения личных Google-дисков (для обмена файлами).
Импортирование модулей и пакетов
В этом примере в блокнот загружаются только необходимые пакеты, и нам нужно несколько конкретных библиотек для работы с общим диском.
Авторизация Google
from oauth2client.client import GoogleCredentialsfrom google.colab import auth as google_authgoogle_auth.authenticate_user()from google.colab import drivedrive.mount('/content/gdrive')
Использование oauth2client и учетных данных Google упростит работу с файлами. Существуют альтернативы, например, скачивание файла JSON с учетными данными, и будут ситуации, когда работа с файлом JSON будет предпочтительнее использования учетных данных Google, но поскольку это проект без конфиденциальных данных, библиотека oauth2client обеспечивает достаточную защиту.
pydrive
from pydrive.auth import GoogleAuthfrom pydrive.drive import GoogleDrivegauth = GoogleAuth()gauth.credentials = GoogleCredentials.get_application_default()drive = GoogleDrive(gauth)
pydrive – это оболочечная библиотека для google-api-python-client, которая упрощает множество общих задач API Google Drive, и одна из этих функциональностей – обработка ответов при запросе файловой системы Google Drive. Google Drive хранит все объекты по идентификаторам, и идентификаторы связаны реляционной информацией в объектах. Возможно получить доступ к этой информации через API (см. следующий блок кода), но оболочка выполняет всю громоздкую работу для нас, когда мы создаем экземпляр GoogleDriveFileList с параметрами Files.list() в виде словаря. Вызов GetList() получит все файлы, соответствующие вашему запросу, в виде списка GoogleDriveFile.
Клиент Google API
# Google API client:from googleapiclient.discovery import build# Инициализация клиента Google Drive APIdrive_service = build('drive', 'v3')
Клиент Google API – это большая библиотека со множеством функциональностей, но для этого проекта нам нужен только один модуль: build. Модуль build создает объект ресурса для взаимодействия с API и возвращает методы для взаимодействия с сервисом. Библиотека pydrive хорошо справляется с основными функциями, такими как создание, обновление и удаление файлов, но в некоторых случаях (в этом проекте) нам требуется более продвинутая функциональность, и доступ к “сервису” позволяет нам извлекать информацию, которую методы pydrive не улавливают.
Это завершает настройку блокнота. В этом примере нам не нужны другие библиотеки, кроме загруженных библиотек для управления файлами, и с загруженными библиотеками мы можем посмотреть, что они делают.
Управление файлами в блокноте
До этого момента произошло несколько вещей:
- Настроена авторизация Google,
- Создан доступ к диску (для чтения/записи), и
- Пакет Pydrive доступен для навигации по диску
Надеюсь, когда вы следуете инструкциям и запускаете код, вы увидите изображение справа, после обновления панели. Вы можете увидеть ярлык на изображении в виде папки под “__Shared”, и мы не видим раздел “Общий доступ ко мне”, но поскольку у нас есть ярлык, нам не нужно видеть файлы “Общий доступ ко мне”.

Google Drive работает по-другому, чем управление файлами в локальных операционных системах, физическое расположение файлов не имеет значения, потому что объекты управляются по ID в неструктурированном DataLake, и мы можем получить доступ к файлам и папкам по ID.
К сожалению, хотя в Python есть функции walk в модуле os.path для обхода файловой системы, подобного метода не существует для Google Drive (или я не знаю об этом методе). Однако мы можем использовать библиотеку pydrive и вручную обходить папки в дереве каталогов, и к счастью, мы знаем, куда мы хотим попасть по пути к папке. Таким образом, нам не нужно просматривать всю структуру, но мы можем использовать имена папок пути данных, чтобы углубиться в дерево папок.
Итак, мы перебираем маленький список (в этом примере три элемента), чтобы найти ID и использовать этот ID для перехода на следующий уровень. Обратите внимание, что четвертый уровень закомментирован; мы дойдем до этого уровня во второй части раздела работы с файлами в этой записной книжке.
# Тестирование обработки файлов:# В этом примере есть три уровня папок:# /content/gdrive/MyDrive/__Shared/<your Project>/DataDevelopment# Обновите их в соответствии со структурой:folderList1 = ["__Shared", your_Project ,"DataDevelopment"] #, "ExternalData"]
Цикл в кодовом блоке ниже начинается в корне, и когда он находит элемент в списке, цикл будет использовать ID объекта для перехода на следующий уровень в списке, и если элемент не найден, код будет сообщать, что папка не найдена, и не будет искать другие папки глубже в структуре. Цикл заканчивается либо ID папки ярлыка, либо сообщает, что папка не найдена.
# Попытка копирования созданного фиктивного файла:boo_foundFolder = FalsefileID = "root"level = 0# Просмотр всех папок и файлов в вашем Google Drive# Сначала переберите список:print("Структура файлов и папок - проверка с ID")for folderName in folderList1: print(f"Проверка: {folderName}") if boo_foundFolder or fileID == "root": #первый запуск boo_foundFolder = False fileList = drive.ListFile({'q': f"'{fileID}' in parents and trashed=false"}).GetList() for file in fileList: # Тестирование имени файла: if(file['title'] == folderName): fileID = file['id'] boo_foundFolder = True level += 1 # end if # end for if boo_foundFolder == False: print(f"папка не найдена") break # end if # end if# end forprint(f"Найдена ли папка: {boo_foundFolder}")if boo_foundFolder: print(fileID) ShortCutID = fileIDelse: ShortCutID = 0
На данный момент у нас есть локальный идентификатор файла для рабочей папки, но прежде чем мы сможем искать файлы в этом месте, нам нужно сопоставить этот локальный идентификатор с целевым идентификатором общей папки. Чтобы найти эту информацию, нам нужен помощник: drive_service. Мы активировали помощник при загрузке проекта, и не получили предупреждения, что означает, что у нас есть доступ к службе, используя API, и запрашивая информацию по ID.
Детали, которые нам нужны, лучше всего собрать с помощью простой функции, например, функции findTargetID
в следующем кодовом блоке. В этой функции fileID
– это ID ярлыка, которое мы нашли, перебирая имена в папках, и вызывая drive_service.files().get
и указывая поля, мы получаем целевой ID папки (этот ID будет таким же, как в URL веб-интерфейса Google Drive (см. Рисунок 1).
def findTargetID(fileID, drive_service): # ID общей папки, для которой нужно получить данные ShortcutDetails file_id = fileID try: # Получение информации о файле file = drive_service.files().get(fileId=file_id, fields="id, shortcutDetails").execute() # Проверка, является ли файл ярлыком if 'shortcutDetails' in file: shortcut_details = file['shortcutDetails'] print("Детали ярлыка:") print(f"ID цели: {shortcut_details['targetId']}") print(f"Целевой MIME-тип: {shortcut_details['targetMimeType']}") else: print("Файл не является ярлыком.") # end if except Exception as e: print(f"Произошла ошибка: {e}") return shortcut_details['targetId']if boo_foundFolder: targetID = findTargetID(fileID, drive_service) print(targetID)else: print("Папка не найдена")# end if
С этим идентификатором цели у нас есть доступ к фактической общей папке на сервере данных Google, и мы больше не работаем с ярлычной папкой.
Повторим, причиной создания ярлычной папки была возможность видеть папку в нашем списке примонтированных папок. Категория “Общие со мной” не примонтирована, но ярлыки примонтированы. Так что с этим новым ID мы можем искать файлы.
Поиск файлов
Теперь у нас есть то, что нам нужно, идентификатор цели папки, которой мы поделились с нами в начале процесса, и с этим ID у нас есть доступ ко всем обычным операциям с файлами.
Мы можем проверить, достаточно ли у нас разрешений на общую папку, сначала создав небольшой текстовый файл в среде выполнения; создание этого файла также подтверждает, что у нас есть доступ к среде выполнения, потому что он появится в левой панели веб-интерфейса блокнота CoLab, когда файл будет правильно создан.
# Создание тестового файла:with open('example.txt', 'w') as f: f.write('Это пример файла для тестирования общего использования файлов CoLab')# этот файл теперь находится в пространстве выполнения блокнота # (см. левую плоскость, под файлами)
Теперь идея заключается в том, чтобы переместить этот файл в папку “Общие со мной” “Данные”, которую мы переименовали в “РазработкаДанных” в ярлычной папке, но функция в предыдущем разделе предоставляла <target ID>, и мы можем использовать этот ID для проверки доступности файла, который мы только что создали в среде выполнения.
if boo_foundFolder: print("папка найдена") folderID = targetID file_on_drive = False file_id = 0 # проверяем, есть ли файл на диске: fileList = drive.ListFile({'q': f"'{folderID}' in parents and trashed=false"}).GetList() for file in fileList: if(file['title'] == "example.txt"): file_on_drive = True fileID = file['id'] # end if # end for if file_on_drive: #Перезаписывает существующий файл Google Drive.""" file1 = drive.CreateFile({'id': fileID}) strFileHandling = "Обновлено" else: file1 = drive.CreateFile({"mimeType": "text/csv", "parents": [{"kind": "drive#fileLink", "id": folderID}]}) strFileHandling = "Создано" # end if # создание привязки к файлу в среде выполнения: file1.SetContentFile("example.txt") # копирование файла на Google Drive: file1.Upload() print(f'{strFileHandling} файл %s с типом MIME %s' % (file1['title'], file1['mimeType']))else: print("папка не найдена")# end if
Запуск кода выше создаст новый файл в общей папке или обновит (перезапишет) файл, когда файл будет найден.
Создание рабочей области
Есть вторая причина использовать идентификатор ярлыка для поиска идентификатора цели, а именно поиск элементов в общей папке. Как уже упоминалось ранее, Google Drive управляет всем по ID, а у идентификатора ярлыка нет дочерних элементов, поэтому использование этого ID для поиска новых элементов приведет к пустому списку. Это можно проверить, включив имя папки “ВнешниеДанные” в первый список папок; первый список не найдет эту папку. Однако повторный запуск цикла с использованием идентификатора цели найдет эту папку.
В приведенном ниже фрагменте кода создается новый список папок, используя имена папок под именем “Общие со мной”. Папка “ВнешниеДанные” доступна (см. рисунок 1), но “НоваяПапкаДанных” еще не создана.
# Обновите их в соответствии с вашей структурой:# ... РазработкаДанных/ВнешниеДанные/__CoLab_Блокнот # Установка рабочей папки:folderList2 = ["ВнешниеДанные", "НоваяПапкаДанных"]
Мы можем использовать ту же структуру цикла, что и раньше, но теперь вместо того, чтобы начинать с КОРНЯ, мы начинаем с идентификатора цели, и цикл найдет папку “ВнешниеДанные”, но не новую папку данных.
Поскольку рабочая папка еще не существует, мы можем использовать drive_service.files
, чтобы создать эту новую папку и с помощью того же метода передавать все файлы из среды выполнения в папку “Общие со мной”.
def create_folder_in_folder(folder_name,parent_folder_id, drive_service): file_metadata = { 'name' : folder_name, 'parents' : [parent_folder_id], 'mimeType' : 'application/vnd.google-apps.folder' } file = drive_service.files().create(body=file_metadata, supportsAllDrives=True, fields='id').execute() print ('Идентификатор папки: %s' % file.get('id'))
if WorkingFolderID == 0: # fileID is the parent ID from the previous search create_folder_in_folder("НоваяПапкаДанных", fileID, drive_service)
Основные выводы: Файловая система Google Диска основана на идентификаторах, и у всех объектов есть свои идентификаторы. Объекты «Поделённые со мной» недоступны в Google Colab, но с помощью «Ярлыка» к ним можно получить доступ, и, найдя связанный Идентификатор цели, можно работать непосредственно с папкой «Поделённые со мной», включая объекты в папке, которая изначально была поделена с нами.
Выводы
В этой статье мы рассмотрели некоторые основные аспекты работы с общими папками, включая:
- Настройка локального управления файлами: Мы начали процесс с получения приглашения на взаимодействие с определенным каталогом Google Диска и показали, как организовать локальную файловую систему для повышения эффективности совместной работы.
- Настройка Google Colab для совместной работы: Мы обсудили преимущества использования Google Colab, совместной среды разработки на языке Python, и показали, как настроить её для совместной работы над проектами.
- Импорт необходимых модулей и пакетов: Мы предоставили примеры кода для импорта основных модулей и пакетов, включая авторизацию Google, pydrive для упрощения задач работы с API Google Диска и клиент API Google для расширенного функционала.
- Управление файлами в блокноте: Вы увидели, как управлять файлами в среде Google Colab, включая создание и перемещение файлов между локальной средой и общими папками с использованием Идентификатора поделённого и Идентификатора цели.
- Поиск файлов и создание рабочих пространств: Мы рассмотрели процесс поиска файлов в общих папках с использованием Идентификаторов целей и создания новых папок и рабочих пространств для ваших проектов.
Надеюсь, этот обзор работы с общими папками и файлами между организациями был полезным и дал некоторые идеи о том, как работать с файлами и папками в общей папке.
Благодарю вас за чтение, и я надеюсь, что этот пост помог вам решить проблему или дал вам идею для следующего проекта.
Ссылка на блокнот Google CoLab: gist
Отказ от ответственности: Код, использованный в этом примере, не оптимизирован, а написан для иллюстрации процесса (любые предложения по улучшению кода приветствуются на страницах gitHub, на которых размещается этот блокнот).