Bildarchivierung, -analyse und -erstellung für Google Workspace & Google Cloud

1. Übersicht

In diesem Codelab wird ein möglicher Unternehmensworkflow vorgestellt: Bildarchivierung, ‑analyse und ‑berichterstellung. Stellen Sie sich vor, Ihre Organisation hat eine Reihe von Bildern, die Speicherplatz auf einer eingeschränkten Ressource belegen. Sie möchten diese Daten archivieren, die Bilder analysieren und vor allem einen Bericht erstellen, in dem die archivierten Standorte und die Ergebnisse der Analyse zusammengefasst und für das Management aufbereitet werden. Google Cloud bietet die Tools, die dafür erforderlich sind, und nutzt APIs aus zwei seiner Produktlinien: Google Workspace (früher G Suite oder Google Apps) und Google Cloud (früher GCP).

In unserem Szenario hat der geschäftliche Nutzer Bilder in Google Drive. Es ist sinnvoll, diese in einem „kälteren“, kostengünstigeren Speicher zu sichern, z. B. in den Speicherklassen, die in Google Cloud Storage verfügbar sind. Mit Google Cloud Vision können Entwickler auf einfache Weise Funktionen zur visuellen Erkennung in Anwendungen einbinden. Hierzu zählen die Erkennung von Objekten und Sehenswürdigkeiten sowie die optische Zeichenerkennung (Optical Character Recognition, OCR). Eine Google-Tabellen-Tabelle ist ein nützliches Visualisierungstool, um all diese Informationen für Ihren Chef zusammenzufassen.

Nachdem Sie dieses Codelab durchlaufen haben, um eine Lösung zu entwickeln, die alle Google Cloud-Produkte nutzt, hoffen wir, dass Sie inspiriert werden, etwas noch Wirkungsvolleres für Ihre Organisation oder Ihre Kunden zu entwickeln.

Lerninhalte

  • Cloud Shell verwenden
  • API-Anfragen authentifizieren
  • Google APIs-Clientbibliothek für Python installieren
  • Google APIs aktivieren
  • Dateien aus Google Drive herunterladen
  • Objekte/Blobs in Cloud Storage hochladen
  • Daten mit Cloud Vision analysieren
  • Zeilen in Google Sheets schreiben

Voraussetzungen

  • Ein Google-Konto (für Google Workspace-Konten ist möglicherweise die Genehmigung durch den Administrator erforderlich)
  • Ein Google Cloud-Projekt mit einem aktiven Google Cloud-Rechnungskonto
  • Kenntnisse von Terminal-/Shell-Befehlen des Betriebssystems
  • Grundlegende Kenntnisse in Python (2 oder 3). Sie können aber auch jede unterstützte Sprache verwenden.

Erfahrung mit den vier oben aufgeführten Google Cloud-Produkten ist hilfreich, aber nicht zwingend erforderlich. Wenn Sie Zeit haben, sich zuerst separat mit den beiden vertraut zu machen, können Sie für jede ein Codelab durcharbeiten, bevor Sie die Übung hier in Angriff nehmen:

Umfrage

Wie werden Sie diese Anleitung verwenden?

Nur lesen Lesen und Übungen durchführen

Wie würden Sie Ihre Erfahrung mit Python bewerten?

Anfänger Mittelstufe Fortgeschrittene

Wie würden Sie Ihre Erfahrungen mit Google Cloud-Diensten bewerten?

Anfänger Mittelstufe Fortgeschrittene

Wie würden Sie Ihre Erfahrungen mit den Google Workspace-Entwicklerdiensten bewerten?

Anfänger Mittelstufe Fortgeschrittene

Möchten Sie lieber „geschäftsorientierte“ Codelabs als Einführungen in Produktfunktionen?

Ja Nein Mehr von beidem

2. Einrichtung und Anforderungen

Umgebung zum selbstbestimmten Lernen einrichten

  1. Melden Sie sich in der Google Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Der Projektname ist der Anzeigename für die Teilnehmer dieses Projekts. Es handelt sich um einen String, der nicht von Google APIs verwendet wird. Sie können ihn jederzeit aktualisieren.
  • Die Projekt-ID muss für alle Google Cloud-Projekte eindeutig sein und ist unveränderlich (kann nach der Festlegung nicht mehr geändert werden). In der Cloud Console wird automatisch ein eindeutiger String generiert. Normalerweise ist es nicht wichtig, wie dieser String aussieht. In den meisten Codelabs müssen Sie auf die Projekt-ID verweisen (sie wird in der Regel als PROJECT_ID angegeben). Wenn Ihnen die generierte ID nicht gefällt, können Sie eine andere zufällige ID generieren. Alternativ können Sie es mit einem eigenen versuchen und sehen, ob es verfügbar ist. Sie kann nach diesem Schritt nicht mehr geändert werden und bleibt für die Dauer des Projekts bestehen.
  • Zur Information: Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu diesen drei Werten
  1. Als Nächstes müssen Sie die Abrechnung in der Cloud Console aktivieren, um Cloud-Ressourcen/-APIs zu verwenden. Die Durchführung dieses Codelabs sollte keine oder nur geringe Kosten verursachen. Wenn Sie Ressourcen herunterfahren möchten, damit Ihnen nach Abschluss dieser Anleitung keine Kosten mehr in Rechnung gestellt werden, können Sie die von Ihnen erstellten Ressourcen oder das gesamte Projekt löschen. Neue Nutzer von Google Cloud kommen für das Programm für kostenlose Testversionen mit einem Guthaben von 300$ infrage.

Cloud Shell starten

Zusammenfassung

Sie können Code zwar lokal auf Ihrem Laptop entwickeln, aber ein zweites Ziel dieses Codelabs ist es, Ihnen die Verwendung von Google Cloud Shell beizubringen, einer Befehlszeilenumgebung, die über Ihren modernen Webbrowser in der Cloud ausgeführt wird.

Cloud Shell aktivieren

  1. Klicken Sie in der Cloud Console auf Cloud Shell aktivieren 853e55310c205094.png.

55efc1aaa7a4d3ad.png

Wenn Sie die Cloud Shell zuvor noch nicht gestartet haben, wird ein Fenster mit einer Beschreibung eingeblendet. Klicken Sie in diesem Fall einfach auf Weiter. So sieht dieses Fenster aus:

9c92662c6a846a5c.png

Das Herstellen der Verbindung mit der Cloud Shell sollte nur wenige Augenblicke dauern.

9f0e51b578fecce5.png

Auf dieser virtuellen Maschine sind alle Entwicklungstools installiert, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft in Google Cloud, was die Netzwerkleistung und Authentifizierung erheblich verbessert. Die meisten, wenn nicht sogar alle Aufgaben in diesem Codelab können mit einem Browser oder Ihrem Chromebook erledigt werden.

Sobald die Verbindung mit der Cloud Shell hergestellt ist, sehen Sie, dass Sie bereits authentifiziert sind und für das Projekt schon Ihre Projekt-ID eingestellt ist.

  1. Führen Sie in der Cloud Shell den folgenden Befehl aus, um zu prüfen, ob Sie authentifiziert sind:
gcloud auth list

Befehlsausgabe

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Führen Sie den folgenden Befehl in Cloud Shell aus, um zu bestätigen, dass der gcloud-Befehl Ihr Projekt kennt:
gcloud config list project

Befehlsausgabe

[core]
project = <PROJECT_ID>

Ist dies nicht der Fall, können Sie die Einstellung mit diesem Befehl vornehmen:

gcloud config set project <PROJECT_ID>

Befehlsausgabe

Updated property [core/project].

3. Python-Umgebung bestätigen

Für dieses Codelab müssen Sie Python verwenden. Die Google APIs-Clientbibliotheken unterstützen jedoch viele Sprachen. Sie können also gern etwas Entsprechendes in Ihrem bevorzugten Entwicklungstool erstellen und Python einfach als Pseudocode verwenden. Dieses Codelab unterstützt Python 2 und 3. Wir empfehlen jedoch, so schnell wie möglich auf Version 3.x umzusteigen.

Die Cloud Shell ist ein praktisches Tool, das Nutzern direkt in der Cloud Console zur Verfügung steht. Da keine lokale Entwicklungsumgebung erforderlich ist, kann diese Anleitung vollständig in der Cloud mit einem Webbrowser durchgearbeitet werden. Speziell für dieses Codelab sind in Cloud Shell bereits beide Versionen von Python vorinstalliert.

In Cloud Shell ist auch IPython installiert. Das ist ein interaktiver Python-Interpreter auf höherer Ebene, den wir besonders für Data Scientists und ML-Experten empfehlen. Wenn das der Fall ist, ist IPython der Standardinterpreter für Jupyter-Notebooks sowie für Colab, von Google Research gehostete Jupyter-Notebooks.

IPython bevorzugt zuerst einen Python 3-Interpreter, greift aber auf Python 2 zurück, wenn 3.x nicht verfügbar ist. Auf IPython kann über Cloud Shell zugegriffen werden. Es kann aber auch in einer lokalen Entwicklungsumgebung installiert werden. Beenden Sie die Shell mit ^D (Strg+D) und bestätigen Sie das Beenden. Die Beispielausgabe beim Starten von ipython sieht so aus:

$ ipython
Python 3.7.3 (default, Mar  4 2020, 23:11:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.13.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

Wenn Sie IPython nicht bevorzugen, können Sie auch einen standardmäßigen interaktiven Python-Interpreter verwenden (entweder Cloud Shell oder Ihre lokale Entwicklungsumgebung). Beenden Sie ihn ebenfalls mit ^D:

$ python
Python 2.7.13 (default, Sep 26 2018, 18:42:22)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 
$ python3
Python 3.7.3 (default, Mar 10 2020, 02:33:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Im Codelab wird außerdem davon ausgegangen, dass Sie das Installationsprogramm pip (Python-Paketmanager und Abhängigkeitsresolver) haben. Es ist in den Versionen 2.7.9+ oder 3.4+ enthalten. Wenn Sie eine ältere Python-Version haben, finden Sie in dieser Anleitung Installationsanweisungen. Je nach Ihren Berechtigungen benötigen Sie möglicherweise sudo- oder Superuser-Zugriff. Das ist aber in der Regel nicht der Fall. Sie können auch explizit pip2 oder pip3 verwenden, um pip für bestimmte Python-Versionen auszuführen.

Im restlichen Codelab wird davon ausgegangen, dass Sie Python 3 verwenden. Für Python 2 werden spezifische Anleitungen bereitgestellt, wenn sie sich erheblich von 3.x unterscheiden.

[Optional] Virtuelle Umgebungen erstellen und verwenden

Dieser Abschnitt ist optional und nur für Nutzer erforderlich, die für dieses Codelab eine virtuelle Umgebung verwenden müssen (siehe Warnung in der Seitenleiste oben). Wenn Sie nur Python 3 auf Ihrem Computer haben, können Sie einfach diesen Befehl ausführen, um eine virtuelle Umgebung mit dem Namen my_env zu erstellen (Sie können auch einen anderen Namen auswählen):

virtualenv my_env

Wenn Sie jedoch sowohl Python 2 als auch Python 3 auf Ihrem Computer haben, empfehlen wir, eine virtuelle Python 3-Umgebung zu installieren. Das geht mit -p flag so:

virtualenv -p python3 my_env

Geben Sie die neu erstellte virtuelle Umgebung ein, indem Sie sie so „aktivieren“:

source my_env/bin/activate

Prüfen Sie, ob Sie sich in der Umgebung befinden. Der Name der Umgebung sollte jetzt vor der Shell-Eingabeaufforderung stehen, z. B.:

(my_env) $ 

Jetzt sollten Sie alle erforderlichen Pakete pip install können, Code in dieser Umgebung ausführen usw. Ein weiterer Vorteil ist, dass Sie diese gesamte Umgebung löschen können, ohne dass sich dies auf den Rest Ihres Systems auswirkt, wenn Sie sie vollständig durcheinanderbringen oder Ihre Python-Installation beschädigt wird.

4. Google APIs-Clientbibliothek für Python installieren

Für dieses Codelab ist die Google APIs-Clientbibliothek für Python erforderlich. Die Installation ist entweder ganz einfach oder Sie müssen gar nichts tun.

Wir haben Ihnen zuvor empfohlen, Cloud Shell zu verwenden. Sie können das gesamte Tutorial über einen Webbrowser in der Cloud durcharbeiten. Ein weiterer Grund für die Verwendung von Cloud Shell ist, dass viele gängige Entwicklungstools und erforderliche Bibliotheken bereits vorinstalliert sind.

*Clientbibliotheken installieren

Optional: Dieser Schritt kann übersprungen werden, wenn Sie Cloud Shell oder eine lokale Umgebung verwenden, in der Sie die Clientbibliotheken bereits installiert haben. Das ist nur erforderlich, wenn Sie lokal entwickeln und die Tools noch nicht installiert haben oder sich nicht sicher sind, ob sie installiert sind. Am einfachsten ist es, pip (oder pip3) für die Installation zu verwenden. Bei Bedarf wird dabei auch pip aktualisiert:

pip install -U pip google-api-python-client oauth2client

Installation bestätigen

Mit diesem Befehl wird die Clientbibliothek sowie alle Pakete installiert, von denen sie abhängt. Unabhängig davon, ob Sie Cloud Shell oder Ihre eigene Umgebung verwenden, prüfen Sie, ob die Clientbibliothek installiert ist. Importieren Sie dazu die erforderlichen Pakete und bestätigen Sie, dass keine Importfehler (und keine Ausgabe) vorhanden sind:

python3 -c "import googleapiclient, httplib2, oauth2client"

Wenn Sie stattdessen Python 2 (über Cloud Shell) verwenden, erhalten Sie eine Warnung, dass die Unterstützung dafür eingestellt wurde:

*******************************************************************************
Python 2 is deprecated. Upgrade to Python 3 as soon as possible.
See https://cloud.google.com/python/docs/python2-sunset

To suppress this warning, create an empty ~/.cloudshell/no-python-warning file.
The command will automatically proceed in  seconds or on any key.
*******************************************************************************

Sobald Sie diesen „Test“-Befehl für den Import erfolgreich ausführen können (keine Fehler/Ausgabe), können Sie mit Google APIs interagieren.

Zusammenfassung

Da es sich um ein Codelab für Fortgeschrittene handelt, wird davon ausgegangen, dass Sie bereits Erfahrung mit dem Erstellen und Verwenden von Projekten in der Konsole haben. Wenn Sie noch keine Erfahrung mit Google APIs und insbesondere Google Workspace APIs haben, sollten Sie zuerst das Google Workspace APIs-Codelab für Einsteiger durcharbeiten. Wenn Sie außerdem wissen, wie Sie Anmeldedaten für ein Nutzerkonto (nicht Dienstkonto) erstellen oder wiederverwenden, legen Sie die Datei client_secret.json in Ihrem Arbeitsverzeichnis ab, überspringen Sie das nächste Modul und fahren Sie mit „Google APIs aktivieren“ fort.

5. *API-Anfragen autorisieren (Nutzerautorisierung)

Dieser Abschnitt kann übersprungen werden, wenn Sie bereits Anmeldedaten für die Nutzerkontoautorisierung erstellt haben und mit dem Vorgang vertraut sind. Sie unterscheidet sich von der Dienstkontoautorisierung, deren Technik sich unterscheidet. Lesen Sie daher bitte unten weiter.

Einführung in die Autorisierung (und einige Authentifizierungen)

Für Anfragen an die APIs muss Ihre Anwendung die entsprechende Autorisierung haben. Authentifizierung ist ein ähnliches Wort und beschreibt Anmeldedaten. Sie authentifizieren sich, wenn Sie sich mit einem Nutzernamen und einem Passwort in Ihrem Google-Konto anmelden. Nach der Authentifizierung muss geprüft werden, ob Sie bzw. Ihr Code autorisiert sind, auf Daten zuzugreifen, z. B. auf Blob-Dateien in Cloud Storage oder auf die persönlichen Dateien eines Nutzers in Google Drive.

Google APIs unterstützen verschiedene Arten der Autorisierung. Die häufigste für G Suite API-Nutzer ist die Nutzerautorisierung, da die Beispielanwendung in diesem Codelab auf Daten von Endnutzern zugreift. Diese Endnutzer müssen Ihrer App die Berechtigung zum Zugriff auf ihre Daten erteilen. Das bedeutet, dass Ihr Code OAuth2-Anmeldedaten für das Nutzerkonto abrufen muss.

Wenn Sie OAuth2-Anmeldedaten für die Nutzerautorisierung abrufen möchten, kehren Sie zum API-Manager zurück und wählen Sie in der linken Navigationsleiste den Tab „Anmeldedaten“ aus:

635af008256d323.png

Dort sehen Sie alle Ihre Anmeldedaten in drei separaten Bereichen:

fd2f4133b406d572.png

Die erste ist für API-Schlüssel, die zweite für OAuth 2.0-Client-IDs und die letzte für OAuth2-Dienstkonten. Wir verwenden die mittlere.

Anmeldedaten erstellen

Klicken Sie auf der Seite „Anmeldedaten“ oben auf die Schaltfläche + Anmeldedaten erstellen. Daraufhin wird ein Dialogfeld geöffnet, in dem Sie „OAuth-Client-ID“ auswählen können:

b17b663668e38787.png

Auf dem nächsten Bildschirm haben Sie zwei Möglichkeiten: Sie können den Zustimmungsbildschirm für die Autorisierung Ihrer App konfigurieren und den Anwendungstyp auswählen:

4e0b967c9d70d262.png

Wenn Sie keinen Zustimmungsbildschirm festgelegt haben, wird die Warnung in der Konsole angezeigt und Sie müssen dies jetzt tun. Überspringen Sie die nächsten Schritte, wenn Ihr Zustimmungsbildschirm bereits eingerichtet wurde.

Klicken Sie auf „Zustimmungsbildschirm konfigurieren“ und wählen Sie eine „Externe“ App aus (oder „Intern“, wenn Sie G Suite-Kunde sind):

f17e97b30d994b0c.png

Für diese Übung spielt es keine Rolle, welche Option Sie auswählen, da Sie Ihr Codelab-Beispiel nicht veröffentlichen. Die meisten Nutzer wählen „Extern“ aus und gelangen so zu einem komplexeren Bildschirm. Sie müssen jedoch nur das Feld „Anwendungsname“ oben ausfüllen:

b107ab81349bdad2.png

Sie benötigen zu diesem Zeitpunkt nur einen Anwendungsnamen. Wählen Sie einen Namen aus, der das Codelab widerspiegelt, das Sie gerade durchführen, und klicken Sie dann auf Speichern.

OAuth-Client-ID erstellen (Nutzerkontoautorisierung)

Kehren Sie nun zum Tab „Anmeldedaten“ zurück, um eine OAuth2-Client-ID zu erstellen. Hier sehen Sie verschiedene OAuth-Client-IDs, die Sie erstellen können:

5ddd365ac0af1e34.png

Wir entwickeln ein Befehlszeilentool, das als Andere eingestuft wird. Wählen Sie diese Option aus und klicken Sie auf die Schaltfläche Erstellen. Wählen Sie einen Client-ID-Namen aus, der die App widerspiegelt, die Sie erstellen, oder übernehmen Sie einfach den Standardnamen, der in der Regel „Anderer Client N“ lautet.

Anmeldedaten speichern

  1. Ein Dialogfeld mit den neuen Anmeldedaten wird angezeigt. Klicken Sie auf OK, um es zu schließen.

8bec84d82cb104d7.png

  1. Scrollen Sie auf der Seite „Anmeldedaten“ nach unten zum Bereich „OAuth 2.0-Client-IDs“ und klicken Sie ganz rechts unten neben der neu erstellten Client-ID auf das Downloadsymbol f54b28417901b3aa.png1b4e8d248274a338.png
  2. Daraufhin wird ein Dialogfeld geöffnet, in dem Sie eine Datei mit dem Namen client_secret-LONG-HASH-STRING.apps.googleusercontent.com.json speichern können, wahrscheinlich im Ordner Downloads. Wir empfehlen, den Namen zu kürzen, z. B. zu client_secret.json (wie in der Beispiel-App verwendet). Speichern Sie die Datei dann in dem Verzeichnis/Ordner, in dem Sie die Beispiel-App in diesem Codelab erstellen.

Zusammenfassung

Jetzt können Sie die in diesem Codelab verwendeten Google-APIs aktivieren. Außerdem haben wir für den Anwendungsnamen im OAuth-Zustimmungsbildschirm „Vision API-Demo“ ausgewählt. Dieser Name wird also in einigen der folgenden Screenshots zu sehen sein.

6. Google APIs aktivieren

In diesem Codelab werden vier Google Cloud-APIs verwendet, zwei aus Google Cloud (Cloud Storage und Cloud Vision) und zwei aus Google Workspace (Google Drive und Google Sheets). Unten finden Sie eine allgemeine Anleitung zum Aktivieren von Google-APIs. Wenn Sie wissen, wie Sie eine API aktivieren, ist das bei den anderen ähnlich.

Unabhängig davon, welche Google-API Sie in Ihrer Anwendung verwenden möchten, muss sie aktiviert sein. APIs können über die Befehlszeile oder über die Cloud Console aktiviert werden. Das Aktivieren von APIs ist immer gleich. Wenn Sie also eine API aktiviert haben, können Sie andere auf ähnliche Weise aktivieren.

Option 1: gcloud-Befehlszeile (Cloud Shell oder lokale Umgebung)

Das Aktivieren von APIs über die Cloud Console ist zwar üblicher, aber einige Entwickler bevorzugen es, alles über die Befehlszeile zu erledigen. Dazu müssen Sie den „Dienstnamen“ einer API nachschlagen. Sie sieht aus wie eine URL: SERVICE_NAME.googleapis.com. Sie finden sie in der Tabelle mit unterstützten Produkten oder können sie programmatisch mit der Google Discovery API abfragen.

Mit diesen Informationen können Sie in Cloud Shell (oder in Ihrer lokalen Entwicklungsumgebung mit dem gcloud-Befehlszeilentool) eine API oder einen Dienst so aktivieren:

gcloud services enable SERVICE_NAME.googleapis.com

Beispiel 1:Cloud Vision API aktivieren

gcloud services enable vision.googleapis.com

Beispiel 2:Aktivieren der serverlosen Compute-Plattform Google App Engine

gcloud services enable appengine.googleapis.com

Beispiel 3:Mehrere APIs mit einer Anfrage aktivieren. Wenn die Zuschauer in diesem Codelab beispielsweise eine App mit der Cloud Translation API in App Engine, Cloud Functions und Cloud Run bereitstellen, lautet die Befehlszeile:

gcloud services enable appengine.googleapis.com cloudfunctions.googleapis.com artifactregistry.googleapis.com run.googleapis.com translate.googleapis.com

Mit diesem Befehl werden App Engine, Cloud Functions, Cloud Run und die Cloud Translation API aktiviert. Außerdem wird die Cloud Artifact Registry aktiviert, da Container-Images vom Cloud Build-System registriert werden müssen, um in Cloud Run bereitgestellt zu werden.

Es gibt auch einige Befehle, mit denen Sie abfragen können, welche APIs aktiviert werden müssen oder welche APIs bereits für Ihr Projekt aktiviert wurden.

Beispiel 4:Abfrage von Google-APIs, die für Ihr Projekt aktiviert werden können

gcloud services list --available --filter="name:googleapis.com"

Beispiel 5:Abfrage nach Google-APIs, die für Ihr Projekt aktiviert sind

gcloud services list

Weitere Informationen zu den oben genannten Befehlen finden Sie in der Dokumentation zum Aktivieren und Deaktivieren von Diensten und zum Auflisten von Diensten.

Option 2: Cloud Console

Sie können die Google-APIs auch im API Manager aktivieren. Rufen Sie in der Cloud Console den API Manager auf. Auf dieser Dashboardseite finden Sie einige Traffic-Informationen für Ihre App, Diagramme mit Anwendungsanfragen, von Ihrer App generierte Fehler und die Reaktionszeiten Ihrer App:

df4a0a5e00d29ffc.png

Unter diesen Diagrammen finden Sie eine Liste der für Ihr Projekt aktivierten Google-APIs:

5fcf10e5a05cfb97.png

Wenn Sie APIs aktivieren oder deaktivieren möchten, klicken Sie oben auf APIs und Dienste aktivieren:

eef4e5e863f4db66.png

Alternativ können Sie in der linken Navigationsleiste APIs & Dienste → Bibliothek auswählen:

6eda5ba145b30b97.png

In beiden Fällen gelangen Sie zur Seite API-Bibliothek:

5d4f1c8e7cf8df28.png

Geben Sie einen API-Namen ein, um danach zu suchen und übereinstimmende Ergebnisse zu sehen:

35bc4b9cf72ce9a4.png

Wählen Sie die API aus, die Sie aktivieren möchten, und klicken Sie auf die Schaltfläche Aktivieren:

9574a69ef8d9e8d2.png

Das Aktivieren aller APIs ist ähnlich, unabhängig davon, welche Google API Sie verwenden möchten.

Kosten

Viele Google-APIs können kostenlos verwendet werden. Für die meisten Google Cloud-Produkte und ‑APIs fallen jedoch Kosten an. Wenn Sie Cloud APIs aktivieren, werden Sie möglicherweise aufgefordert, ein aktives Rechnungskonto anzugeben. Für einige Google Cloud-Produkte gibt es jedoch eine kostenlose Stufe, die Sie überschreiten müssen, damit Abrechnungsgebühren anfallen.

Neue Google Cloud-Nutzer kommen für den kostenlosen Testzeitraum infrage, der derzeit 300 $umfasst und für die ersten 90 Tage gilt. Für Codelabs fallen in der Regel keine oder nur geringe Kosten an. Wir empfehlen Ihnen daher, mit der kostenlosen Testphase zu warten, bis Sie sie wirklich nutzen möchten, da es sich um ein einmaliges Angebot handelt. Die Kontingente für die Kostenlose Stufe laufen nicht ab und gelten unabhängig davon, ob Sie den kostenlosen Testzeitraum nutzen oder nicht.

Nutzer sollten sich die Preisinformationen für jede API ansehen, bevor sie sie aktivieren (z. B. die Seite Cloud Vision API-Preise ). Dabei sollten sie insbesondere darauf achten, ob es ein kostenloses Kontingent gibt und wie hoch es ist. Solange Sie die angegebenen täglichen oder monatlichen Grenzwerte insgesamt nicht überschreiten, sollten keine Gebühren anfallen. Die Preise und kostenlosen Stufen variieren je nach API der Google-Produktgruppe. Beispiele:

Die Abrechnung für die verschiedenen Google-Produkte erfolgt unterschiedlich. Sehen Sie daher in der entsprechenden Dokumentation nach.

Zusammenfassung

Nachdem Sie Cloud Vision aktiviert haben, aktivieren Sie die anderen drei APIs (Google Drive, Cloud Storage, Google Sheets) auf dieselbe Weise. Verwenden Sie in Cloud Shell gcloud services enable oder in der Cloud Console:

  1. Zurück zur API-Bibliothek
  2. Suche starten, indem du einige Buchstaben des Namens eingibst
  3. Wählen Sie die gewünschte API aus.
  4. Aktivieren

Einseifen, ausspülen und wiederholen. Für Cloud Storage gibt es mehrere Optionen. Wählen Sie die „Google Cloud Storage JSON API“ aus. Für die Cloud Storage API ist ebenfalls ein aktives Abrechnungskonto erforderlich.

7. Schritt 0: Importe und Autorisierungscode einrichten

Dies ist der Beginn eines mittelgroßen Codeabschnitts. Wenn Sie also agile Methoden anwenden, können Sie dafür sorgen, dass eine gemeinsame, stabile und funktionierende Infrastruktur vorhanden ist, bevor Sie sich mit der Hauptanwendung befassen. Prüfen Sie, ob client_secret.json in Ihrem aktuellen Verzeichnis verfügbar ist. Starten Sie entweder ipython und geben Sie das folgende Code-Snippet ein oder speichern Sie es in analyze_gsimg.py und führen Sie es über die Shell aus. Letzteres ist vorzuziehen, da wir dem Codebeispiel weitere Elemente hinzufügen werden:

from __future__ import print_function

from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools

# process credentials for OAuth2 tokens
SCOPES = 'https://www.googleapis.com/auth/drive.readonly'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
    creds = tools.run_flow(flow, store)

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)

Diese Kernkomponente enthält Codeblöcke für Modul-/Paketimporte, die Verarbeitung von Nutzeranmeldedaten und das Erstellen von API-Dienstendpunkten. Die wichtigsten Codeabschnitte, die Sie überprüfen sollten:

  • Durch das Importieren der print()-Funktion ist dieses Beispiel mit Python 2 und 3 kompatibel. Durch die Google-Bibliotheksimporte werden alle Tools bereitgestellt, die für die Kommunikation mit Google-APIs erforderlich sind.
  • Die Variable SCOPES steht für die Berechtigungen, die vom Nutzer angefordert werden. Derzeit gibt es nur eine: die Berechtigung, Daten aus seinem Google Drive zu lesen.
  • Im restlichen Code für die Verarbeitung von Anmeldedaten werden im Cache gespeicherte OAuth2-Tokens gelesen und möglicherweise mit dem Aktualisierungstoken auf ein neues Zugriffstoken aktualisiert, wenn das ursprüngliche Zugriffstoken abgelaufen ist.
  • Wenn keine Tokens erstellt wurden oder das Abrufen eines gültigen Zugriffstokens aus einem anderen Grund fehlgeschlagen ist, muss der Nutzer den OAuth2-Ablauf mit drei Schritten durchlaufen: Erstellen Sie den Dialog mit den angeforderten Berechtigungen und fordern Sie den Nutzer auf, ihn zu akzeptieren. Andernfalls löst tools.run_flow() eine Ausnahme aus und die Ausführung wird angehalten.
  • Sobald der Nutzer die Berechtigung erteilt hat, wird ein HTTP-Client für die Kommunikation mit dem Server erstellt und alle Anfragen werden aus Sicherheitsgründen mit den Anmeldedaten des Nutzers signiert. Anschließend wird mit diesem HTTP-Client ein Dienstendpunkt für die Google Drive API (Version 3) erstellt und DRIVE zugewiesen.

Anwendung ausführen

Wenn Sie das Script zum ersten Mal ausführen, hat es keine Autorisierung für den Zugriff auf die Dateien des Nutzers (Ihre) in Drive. Die Ausgabe sieht so aus, wenn die Ausführung pausiert wird:

$ python3 ./analyze_gsimg.py
/usr/local/lib/python3.6/site-packages/oauth2client/_helpers.py:255: UserWarning: Cannot access storage.json: No such file or directory
  warnings.warn(_MISSING_FILE_MESSAGE.format(filename))

Your browser has been opened to visit:
    https://accounts.google.com/o/oauth2/auth?client_id=LONG-STRING.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly&access_type=offline&response_type=code

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

Wenn Sie Cloud Shell verwenden, fahren Sie mit dem Abschnitt „Über Cloud Shell“ fort und kehren Sie bei Bedarf zu den relevanten Screenshots im Abschnitt „Über lokale Entwicklungsumgebung“ zurück.

Aus der lokalen Entwicklungsumgebung

Das Befehlszeilenscript wird angehalten, wenn ein Browserfenster geöffnet wird. Möglicherweise wird eine Warnseite angezeigt, die so aussieht:

149241d33871a141.png

Das ist ein berechtigter Einwand, da Sie versuchen, eine App auszuführen, die auf Nutzerdaten zugreift. Da es sich nur um eine Demo-App handelt und Sie der Entwickler sind, vertrauen Sie sich hoffentlich genug, um fortzufahren. Stellen Sie sich vor, Sie werden aufgefordert, den Code einer anderen Person auf Ihre Daten zugreifen zu lassen. Wenn Sie eine solche App veröffentlichen möchten, müssen Sie den Prüfprozess durchlaufen, damit Ihre Nutzer diesen Bildschirm nicht sehen.

Nachdem Sie auf den Link „Zur unsicheren App“ geklickt haben, wird ein OAuth2-Berechtigungsdialogfeld angezeigt, das in etwa so aussieht wie unten. Wir verbessern unsere Benutzeroberfläche ständig. Wenn das Dialogfeld also nicht genau so aussieht, ist das kein Problem.

a122eb7468d0d34e.png

Im OAuth2-Ablaufdialogfeld werden die Berechtigungen angezeigt, die der Entwickler anfordert (über die Variable SCOPES). In diesem Fall ist es die Möglichkeit, die Google Drive-Inhalte des Nutzers anzusehen und herunterzuladen. Im Anwendungscode werden diese Berechtigungsbereiche als URIs angezeigt, sie werden aber in die Sprache übersetzt, die durch die Sprache des Nutzers angegeben wird. Hier muss der Nutzer die angeforderten Berechtigungen explizit autorisieren. Andernfalls wird eine Ausnahme ausgelöst und das Script wird nicht fortgesetzt.

Möglicherweise wird ein weiteres Dialogfeld angezeigt, in dem Sie um Bestätigung gebeten werden:

bf171080dcd6ec5.png

NOTE: Einige Nutzer verwenden mehrere Webbrowser, in denen sie in verschiedenen Konten angemeldet sind. Daher wird diese Autorisierungsanfrage möglicherweise an den falschen Browsertab oder das falsche Browserfenster gesendet. Sie müssen den Link für diese Anfrage dann möglicherweise in einen Browser kopieren, in dem Sie mit dem richtigen Konto angemeldet sind.

Über Cloud Shell

In Cloud Shell wird kein Browserfenster geöffnet, sodass Sie nicht fortfahren können. Sie stellen fest, dass die Diagnosemeldung unten für Sie bestimmt war:

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

Sie müssen ^C (Strg+C oder eine andere Tastenkombination zum Beenden der Skriptausführung) drücken und das Skript mit dem zusätzlichen Flag über die Shell ausführen. Wenn Sie den Code auf diese Weise ausführen, erhalten Sie stattdessen die folgende Ausgabe:

$ python3 analyze_gsimg.py --noauth_local_webserver
/usr/local/lib/python3.7/site-packages/oauth2client/_helpers.py:255: UserWarning: Cannot access storage.json: No such file or directory
  warnings.warn(_MISSING_FILE_MESSAGE.format(filename))

Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?client_id=LONG-STRING.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly&access_type=offline&response_type=code

Enter verification code:

(Wir ignorieren die Warnung, da wir wissen, dass storage.json noch nicht erstellt wurde.) Wenn Sie der Anleitung auf einem anderen Tab mit dieser URL folgen, erhalten Sie eine Benutzeroberfläche, die der oben beschriebenen für lokale Entwicklungsumgebungen nahezu identisch ist (siehe Screenshots oben). Am Ende wird ein letzter Bildschirm mit dem Bestätigungscode angezeigt, der in Cloud Shell eingegeben werden muss:

40a567cda0f31cc9.png

Kopieren Sie diesen Code und fügen Sie ihn in das Terminalfenster ein.

Zusammenfassung

Außer „Authentication successful“ sollten Sie keine zusätzliche Ausgabe erwarten. Denken Sie daran, dass dies nur die Einrichtung ist. Sie haben noch nichts getan. Sie haben bereits den ersten Schritt auf dem Weg zu etwas getan, das mit größerer Wahrscheinlichkeit beim ersten Mal richtig ausgeführt wird. Das Beste daran ist, dass Sie nur einmal zur Autorisierung aufgefordert wurden. Bei allen nachfolgenden Ausführungen wird sie übersprungen, da Ihre Berechtigungen im Cache gespeichert wurden. Jetzt lassen wir den Code etwas leisten, sodass eine tatsächliche Ausgabe erfolgt.

Fehlerbehebung

Wenn Sie eine Fehlermeldung anstelle einer Ausgabe erhalten, kann das verschiedene Ursachen haben, z. B.:

8. Schritt 1: Bild aus Google Drive herunterladen

Im vorherigen Schritt haben wir empfohlen, den Code als analyze_gsimg.py zu erstellen und ihn dann zu bearbeiten. Es ist auch möglich, alles direkt in iPython oder die Standard-Python-Shell zu kopieren und einzufügen. Das ist jedoch umständlicher, da wir die App nach und nach erstellen.

Angenommen, Ihre App wurde autorisiert und der API-Dienstendpunkt wurde erstellt. Im Code wird sie durch die Variable DRIVE dargestellt. Suchen Sie nun in Google Drive nach einer Bilddatei und

Weisen Sie den Wert einer Variablen mit der Bezeichnung NAME zu. Geben Sie das ein sowie die folgende drive_get_img()-Funktion direkt unter dem Code aus Schritt 0:

FILE = 'YOUR_IMG_ON_DRIVE'  # fill-in with name of your Drive file

def drive_get_img(fname):
    'download file from Drive and return file info & binary if found'

    # search for file on Google Drive
    rsp = DRIVE.files().list(q="name='%s'" % fname,
            fields='files(id,name,mimeType,modifiedTime)'
    ).execute().get('files', [])

    # download binary & return file info if found, else return None
    if rsp:
        target = rsp[0]  # use first matching file
        fileId = target['id']
        fname = target['name']
        mtype = target['mimeType']
        binary = DRIVE.files().get_media(fileId=fileId).execute()
        return fname, mtype, target['modifiedTime'], binary

Die Drive-Sammlung files() hat eine Methode list(), mit der eine Anfrage (der Parameter q) für die angegebene Datei ausgeführt wird. Mit dem Parameter fields geben Sie an, welche Rückgabewerte Sie interessieren. Warum sollten Sie alle Werte abrufen und die Verarbeitung verlangsamen, wenn Sie sich nicht für die anderen Werte interessieren? Wenn Sie Feldmasken zum Filtern von API-Rückgabewerten noch nicht kennen, sehen Sie sich diesen Blogpost und dieses Video an. Andernfalls wird die Abfrage ausgeführt und das zurückgegebene Attribut files abgerufen. Wenn es keine Übereinstimmungen gibt, wird standardmäßig ein leeres Listenarray zurückgegeben.

Wenn keine Ergebnisse vorhanden sind, wird der Rest der Funktion übersprungen und None wird (implizit) zurückgegeben. Andernfalls wird die erste übereinstimmende Antwort (rsp[0]) abgerufen und der Dateiname, der MIME-Typ, der Zeitstempel der letzten Änderung und schließlich die binäre Nutzlast zurückgegeben, die von der Funktion get_media() (über die Datei-ID) ebenfalls in der Sammlung files() abgerufen wird. Die Methodennamen können in anderen Sprach-Clientbibliotheken leicht abweichen.

Der letzte Teil ist der „main“-Teil, der die gesamte Anwendung steuert:

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

Wenn Sie davon ausgehen, dass ein Bild mit dem Namen section-work-card-img_2x.jpg in Drive gespeichert ist und auf FILE festgelegt wurde, sollte nach erfolgreicher Ausführung des Skripts eine Ausgabe angezeigt werden, die bestätigt, dass die Datei aus Drive gelesen werden konnte (aber nicht auf Ihrem Computer gespeichert wurde):

$ python3 analyze_gsimg.py
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)

Fehlerbehebung

Wenn Sie nicht die oben gezeigte Ausgabe erhalten, kann das einen oder mehrere Gründe haben, z. B. den folgenden:

Zusammenfassung

In diesem Abschnitt haben Sie gelernt, wie Sie in zwei separaten API-Aufrufen eine Verbindung zur Drive API herstellen, um eine bestimmte Datei abzufragen und dann herunterzuladen. Geschäftlicher Anwendungsfall: Drive-Daten archivieren und analysieren, z. B. mit Google Cloud-Tools. Der Code für Ihre App sollte in dieser Phase dem Code im Repositorystep1-drive/analyze_gsimg.py entsprechen.

Weitere Informationen zum Herunterladen von Dateien in Google Drive finden Sie in diesem Blogpost und Video. Dieser Teil des Codelabs ist fast identisch mit dem gesamten Codelab zur Einführung in Google Workspace APIs. Anstatt eine Datei herunterzuladen, werden die ersten 100 Dateien/Ordner im Google Drive eines Nutzers angezeigt und es wird ein restriktiverer Bereich verwendet.

9. Schritt 2: Datei in Cloud Storage archivieren

Im nächsten Schritt fügen Sie Unterstützung für Google Cloud Storage hinzu. Dazu müssen wir ein weiteres Python-Paket importieren: io. Der obere Teil Ihrer Importe sollte jetzt so aussehen:

from __future__ import print_function                   
import io

Zusätzlich zum Drive-Dateinamen benötigen wir einige Informationen dazu, wo diese Datei in Cloud Storage gespeichert werden soll, insbesondere den Namen des Buckets, in den Sie sie einfügen möchten, und alle Präfixe für übergeordnete Ordner. Dazu gleich mehr:

FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX                  

Ein Wort zu Buckets: Cloud Storage bietet amorphen Blob-Speicher. Beim Hochladen von Dateien in diesen Bereich werden Dateitypen, Erweiterungen usw. nicht wie in Google Drive berücksichtigt. Für Cloud Storage sind sie nur „Blobs“. Außerdem gibt es in Cloud Storage kein Konzept für Ordner oder Unterverzeichnisse.

Ja, Sie können Schrägstriche (/) in Dateinamen verwenden, um die Abstraktion mehrerer Unterordner darzustellen. Letztendlich werden jedoch alle Ihre Blobs in einem Bucket gespeichert und „/“ sind nur Zeichen in ihren Dateinamen. Weitere Informationen finden Sie auf der Seite Benennungsrichtlinien für Buckets und Objekte.

In Schritt 1 oben wurde der schreibgeschützte Drive-Bereich angefordert. Das war damals alles, was Sie brauchten. Jetzt ist die Berechtigung zum Hochladen (Lesen und Schreiben) in Cloud Storage erforderlich. Ändern Sie SCOPES von einer einzelnen Stringvariablen in ein Array (Python-Tupel [oder ‑Liste]) von Berechtigungsbereichen, sodass es so aussieht:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
)                  

Erstellen Sie nun direkt unter dem für Drive einen Dienstendpunkt für Cloud Storage. Wir haben den Aufruf leicht geändert, um dasselbe HTTP-Clientobjekt wiederzuverwenden, da es nicht erforderlich ist, ein neues zu erstellen, wenn es sich um eine freigegebene Ressource handeln kann.

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)                  

Fügen Sie nun diese Funktion (nach drive_get_img()) hinzu, die in Cloud Storage hochgeladen wird:

def gcs_blob_upload(fname, bucket, media, mimetype):
    'upload an object to a Google Cloud Storage bucket'

    # build blob metadata and upload via GCS API
    body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype}
    return GCS.objects().insert(bucket=bucket, body=body,
            media_body=http.MediaIoBaseUpload(io.BytesIO(media), mimetype),
            fields='bucket,name').execute()

Für den objects.().insert()-Aufruf sind der Bucket-Name, die Dateimetadaten und der binäre Blob selbst erforderlich. Um die Rückgabewerte herauszufiltern, werden mit der Variablen fields nur die Bucket- und Objektnamen angefordert, die von der API zurückgegeben werden. Weitere Informationen zu Feldmasken in API-Leseanfragen finden Sie in diesem Beitrag und Video.

Binden Sie nun die Verwendung von gcs_blob_upload() in die Hauptanwendung ein:

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)

Die Variable gcsname führt alle Namen von übergeordneten Unterverzeichnissen mit dem Dateinamen zusammen. Wenn ihr der Bucket-Name vorangestellt wird, entsteht der Eindruck, dass Sie die Datei unter „/bucket/parent.../filename“ archivieren. Fügen Sie diesen Block direkt nach der ersten print()-Funktion über der else-Klausel ein, damit der gesamte „main“-Block so aussieht:

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

Angenommen, wir geben einen Bucket namens „vision-demo“ mit „analyzed_imgs“ als „übergeordnetes Unterverzeichnis“ an. Wenn Sie diese Variablen festgelegt und das Skript noch einmal ausgeführt haben, wird section-work-card-img_2x.jpg aus Drive heruntergeladen und in Cloud Storage hochgeladen, oder? NICHT!

$ python3 analyze_gsimg.py 
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Traceback (most recent call last):
  File "analyze_gsimg.py", line 85, in <module>
    io.BytesIO(data), mimetype=mtype), mtype)
  File "analyze_gsimg.py", line 72, in gcs_blob_upload
    media_body=media, fields='bucket,name').execute()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/googleapiclient/_helpers.py", line 134, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/googleapiclient/http.py", line 898, in execute
    raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://storage.googleapis.com/upload/storage/v1/b/PROJECT_ID/o?fields=bucket%2Cname&alt=json&uploadType=multipart returned "Insufficient Permission">

Sehen Sie genau hin: Der Download von Drive war erfolgreich, der Upload in Cloud Storage ist jedoch fehlgeschlagen. Warum?

Der Grund dafür ist, dass wir bei der ursprünglichen Autorisierung dieser Anwendung in Schritt 1 nur den Lesezugriff auf Google Drive autorisiert haben. Wir haben zwar den Lese-/Schreibbereich für Cloud Storage hinzugefügt, den Nutzer aber nie aufgefordert, diesen Zugriff zu autorisieren. Dazu müssen wir die Datei storage.json löschen, in der dieser Bereich fehlt, und den Vorgang noch einmal ausführen.

Nachdem Sie die Autorisierung noch einmal durchgeführt haben (bestätigen Sie dies, indem Sie in storage.json nachsehen, ob beide Bereiche vorhanden sind), sollte die Ausgabe wie erwartet aussehen:

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'

Zusammenfassung

Das ist ein großer Vorteil, da Sie in relativ wenigen Codezeilen sehen, wie Sie Dateien zwischen den beiden cloudbasierten Speichersystemen übertragen. Der geschäftliche Anwendungsfall besteht darin, eine möglicherweise eingeschränkte Ressource wie oben beschrieben auf einem „kälteren“, kostengünstigeren Speicher zu sichern. Cloud Storage bietet verschiedene Speicherklassen, je nachdem, ob Sie regelmäßig, monatlich, vierteljährlich oder jährlich auf Ihre Daten zugreifen.

Entwickler fragen uns natürlich immer wieder, warum es sowohl Google Drive als auch Cloud Storage gibt. Schließlich sind sie beide Dateispeicher in der Cloud. Deshalb haben wir dieses Video erstellt. Ihr Code sollte zu diesem Zeitpunkt mit dem Code im Repository unter step2-gcs/analyze_gsimg.py übereinstimmen.

10. Schritt 3: Mit Cloud Vision analysieren

Wir wissen jetzt, dass Sie Daten zwischen Google Cloud und Google Workspace übertragen können. Wir haben aber noch keine Analyse durchgeführt. Es ist also an der Zeit, das Bild zur Label-Annotation, also zur Objekterkennung, an Cloud Vision zu senden. Dazu müssen wir die Daten Base64-codieren. Das bedeutet, dass wir ein weiteres Python-Modul benötigen: base64. Der obere Importabschnitt sollte jetzt so aussehen:

from __future__ import print_function
import base64
import io

Standardmäßig gibt die Vision API alle gefundenen Labels zurück. Um die Dinge konsistent zu halten, fordern wir nur die Top 5 an (die natürlich vom Nutzer angepasst werden können). Wir verwenden dafür die konstante Variable TOP. Fügen Sie sie unter allen anderen Konstanten hinzu:

FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''   # YOUR IMG FILE PREFIX 
TOP = 5       # TOP # of VISION LABELS TO SAVE                 

Wie bei den vorherigen Schritten benötigen wir einen weiteren Berechtigungsbereich, diesmal für die Vision API. Aktualisieren Sie SCOPES mit dem String its:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
)                  

Erstellen Sie nun einen Dienstendpunkt für Cloud Vision, damit er mit den anderen übereinstimmt:

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)

Fügen Sie nun diese Funktion hinzu, die die Bildnutzlast an Cloud Vision sendet:

def vision_label_img(img, top):
    'send image to Vision API for label annotation'

    # build image metadata and call Vision API to process
    body = {'requests': [{
                'image':     {'content': img},
                'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
    }]}
    rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]

    # return top labels for image as CSV for Sheet (row)
    if 'labelAnnotations' in rsp:
        return ', '.join('(%.2f%%) %s' % (
                label['score']*100., label['description']) \
                for label in rsp['labelAnnotations'])

Für den images().annotate()-Aufruf sind die Daten und die gewünschten API-Funktionen erforderlich. Die Obergrenze für die fünf wichtigsten Labels ist ebenfalls Teil der Nutzlast, aber völlig optional. Wenn der Aufruf erfolgreich ist, enthält die Nutzlast die fünf wichtigsten Labels von Objekten sowie einen Konfidenzwert dafür, dass sich ein Objekt im Bild befindet. Wenn keine Antwort zurückgegeben wird, weisen Sie ein leeres Python-Wörterbuch zu, damit die folgende if-Anweisung nicht fehlschlägt. Diese Funktion fasst die Daten einfach in einem CSV-String zusammen, der später in unserem Bericht verwendet wird.

Diese fünf Zeilen, in denen vision_label_img() aufgerufen wird, sollten direkt nach dem erfolgreichen Upload in Cloud Storage platziert werden:

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)

Mit dieser Ergänzung sollte der gesamte Haupttreiber so aussehen:

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), TOP)
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

Wenn Sie storage.json löschen, um die Bereiche zu aktualisieren, und die aktualisierte Anwendung noch einmal ausführen, sollte die Ausgabe in etwa so aussehen. Beachten Sie, dass die Cloud Vision-Analyse hinzugekommen ist:

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'
Top 5 labels from Vision API: (89.94%) Sitting, (86.09%) Interior design, (82.08%) Furniture, (81.52%) Table, (80.85%) Room

Zusammenfassung

Nicht jeder hat das Fachwissen im Bereich maschinelles Lernen, um eigene ML-Modelle zum Analysieren seiner Daten zu erstellen und zu trainieren. Das Google Cloud-Team hat einige der vortrainierten Modelle von Google für die allgemeine Nutzung zur Verfügung gestellt und sie hinter APIs platziert, um KI und ML für alle zugänglich zu machen.

Wenn Sie Entwickler sind und eine API aufrufen können, können Sie maschinelles Lernen nutzen. Cloud Vision ist nur einer der API-Dienste, mit denen Sie Ihre Daten analysieren können. Weitere Informationen Ihr Code sollte jetzt mit dem Code im Repository unterstep3-vision/analyze_gsimg.py übereinstimmen.

11. Schritt 4: Bericht mit Google Tabellen erstellen

Sie haben Unternehmensdaten archiviert und analysiert, aber es fehlt eine Zusammenfassung dieser Arbeit. Lassen Sie uns alle Ergebnisse in einem einzigen Bericht zusammenfassen, den Sie Ihrem Chef geben können. Was ist für das Management ansprechender als eine Tabellenkalkulation?

Für die Google Sheets API sind keine zusätzlichen Importe erforderlich. Die einzige neue Information, die benötigt wird, ist die Datei-ID einer vorhandenen Tabelle, die bereits formatiert ist und auf eine neue Datenzeile wartet. Daher die Konstante SHEET. Wir empfehlen, eine neue Tabelle zu erstellen, die in etwa so aussieht:

4def78583d05300.png

Die URL für diese Tabelle sieht so aus: https://docs.google.com/spreadsheets/d/FILE_ID/edit. Kopieren Sie FILE_ID und weisen Sie es als String SHEET zu.

Außerdem haben wir eine kleine Funktion namens k_ize() eingefügt, die Byte in Kilobyte umwandelt. Da es sich um eine einfache Einzeiler-Funktion handelt, haben wir sie als Python-lambda definiert. Beide integriert mit den anderen Konstanten sieht das so aus:

k_ize =  lambda b: '%6.2fK' % (b/1000.)  # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX
SHEET = 'YOUR_SHEET_ID'
TOP = 5       # TOP # of VISION LABELS TO SAVE                 

Wie bei den vorherigen Schritten benötigen wir einen weiteren Berechtigungsbereich, diesmal Lese-/Schreibzugriff für die Sheets API. SCOPES hat jetzt alle vier erforderlichen:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
    'https://www.googleapis.com/auth/spreadsheets',
)                  

Erstellen Sie nun einen Dienstendpunkt für Google Sheets in der Nähe der anderen, sodass er so aussieht:

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)
SHEETS = discovery.build('sheets',  'v4', http=HTTP)

Die Funktion von sheet_append_row() ist einfach: Sie nimmt eine Datenzeile und die ID eines Tabellenblatts entgegen und fügt die Zeile dann diesem Tabellenblatt hinzu:

def sheet_append_row(sheet, row):
    'append row to a Google Sheet, return #cells added'

    # call Sheets API to write row to Sheet (via its ID)
    rsp = SHEETS.spreadsheets().values().append(
            spreadsheetId=sheet, range='Sheet1',
            valueInputOption='USER_ENTERED', body={'values': [row]}
    ).execute()
    if rsp:
        return rsp.get('updates').get('updatedCells')

Für den spreadsheets().values().append()-Aufruf sind die Datei-ID des Tabellenblatts, ein Zellbereich, die Art der Dateneingabe und die Daten selbst erforderlich. Die Datei-ID ist einfach, der Zellenbereich wird in A1-Schreibweise angegeben. Der Bereich „Sheet1“ bedeutet das gesamte Tabellenblatt. Die API wird dadurch angewiesen, die Zeile nach allen Daten im Tabellenblatt anzuhängen. Es gibt zwei Optionen, wie die Daten in das Tabellenblatt eingefügt werden sollen: „RAW“ (die Stringdaten werden unverändert eingegeben) oder „USER_ENTERED“ (die Daten werden so eingegeben, als ob ein Nutzer sie über die Tastatur in Google Tabellen eingegeben hätte, wobei alle Zellformatierungsfunktionen beibehalten werden).

Wenn der Aufruf erfolgreich ist, ist der Rückgabewert nicht wirklich nützlich. Daher haben wir uns dafür entschieden, die Anzahl der Zellen abzurufen, die durch die API-Anfrage aktualisiert wurden. Hier ist der Code, mit dem diese Funktion aufgerufen wird:

                # push results to Sheet, get cells-saved count
                fsize = k_ize(len(data))
                row = [PARENT,
                        '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
                        BUCKET, gcsname, fname), mtype, ftime, fsize, rsp
                ]
                rsp = sheet_append_row(SHEET, row)
                if rsp:
                    print('Updated %d cells in Google Sheet' % rsp)
                else:
                    print('ERROR: Cannot write row to Google Sheets')

Die Google-Tabelle enthält Spalten mit Daten wie ein übergeordnetes „Unterverzeichnis“, den Speicherort der archivierten Datei in Cloud Storage (Bucket + Dateiname), den MIME-Typ der Datei, die Dateigröße (ursprünglich in Byte, aber mit k_ize() in Kilobyte umgerechnet) und den String mit den Cloud Vision-Labels. Die archivierte Position ist ein Hyperlink. Ihr Manager kann darauf klicken, um zu bestätigen, dass sie sicher gesichert wurde.

Wenn Sie den oben stehenden Codeblock direkt nach der Anzeige der Ergebnisse aus Cloud Vision hinzufügen, ist der Hauptteil der App nun fertig, auch wenn er strukturell etwas komplex ist:

if __name__ == '__main__':
    # download img file & info from Drive
    rsp = drive_get_img(FILE)
    if rsp:
        fname, mtype, ftime, data = rsp
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

        # upload file to GCS
        gcsname = '%s/%s'% (PARENT, fname)
        rsp = gcs_blob_upload(gcsname, BUCKET, data, mtype)
        if rsp:
            print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

            # process w/Vision
            rsp = vision_label_img(base64.b64encode(data).decode('utf-8'))
            if rsp:
                print('Top %d labels from Vision API: %s' % (TOP, rsp))

                # push results to Sheet, get cells-saved count
                fsize = k_ize(len(data))
                row = [PARENT,
                        '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
                        BUCKET, gcsname, fname), mtype, ftime, fsize, rsp
                ]
                rsp = sheet_append_row(SHEET, row)
                if rsp:
                    print('Updated %d cells in Google Sheet' % rsp)
                else:
                    print('ERROR: Cannot write row to Google Sheets')
            else:
                print('ERROR: Vision API cannot analyze %r' % fname)
        else:
            print('ERROR: Cannot upload %r to Cloud Storage' % gcsname)
    else:
        print('ERROR: Cannot download %r from Drive' % fname)

Wenn Sie storage.json ein letztes Mal löschen und die aktualisierte Anwendung noch einmal ausführen, sollte die Ausgabe in etwa so aussehen. Beachten Sie, dass die Cloud Vision-Analyse hinzugefügt wurde:

$ python3 analyze_gsimg.py

    . . .

Authentication successful.
Downloaded 'section-work-card-img_2x.jpg' (image/jpeg, 2020-02-27T09:27:22.095Z, size: 27781)
Uploaded 'analyzed_imgs/section-work-card-img_2x.jpg' to GCS bucket 'vision-demo'
Top 5 labels from Vision API: (89.94%) Sitting, (86.09%) Interior design, (82.08%) Furniture, (81.52%) Table, (80.85%) Room
Updated 6 cells in Google Sheet

Die zusätzliche Zeile in der Ausgabe ist zwar nützlich, lässt sich aber besser visualisieren, wenn Sie sich die aktualisierte Google-Tabelle ansehen. Die letzte Zeile (Zeile 7 im Beispiel unten) wurde dem vorhandenen Datensatz hinzugefügt:

b53a5bc944734652.png

Zusammenfassung

In den ersten drei Schritten dieses Tutorials haben Sie eine Verbindung zu Google Workspace- und Google Cloud-APIs hergestellt, um Daten zu übertragen und zu analysieren. Das entspricht 80% der gesamten Arbeit. Letztendlich ist das alles jedoch bedeutungslos, wenn Sie Ihre Erfolge nicht dem Management präsentieren können. Um die Ergebnisse besser zu visualisieren, ist es hilfreich, sie in einem generierten Bericht zusammenzufassen.

Um die Nützlichkeit der Analyse weiter zu verbessern, könnten die Ergebnisse nicht nur in eine Tabelle geschrieben, sondern auch die fünf wichtigsten Labels für jedes Bild indexiert werden. So könnte eine interne Datenbank erstellt werden, die es autorisierten Mitarbeitern ermöglicht, Bilder nach Suchteam abzufragen. Das überlassen wir jedoch den Lesern.

Derzeit sind unsere Ergebnisse in einem Tabellenblatt verfügbar und für das Management zugänglich. Der Code für Ihre App sollte in dieser Phase dem Code im Repositorystep4-sheets/analyze_gsimg.py entsprechen. Im letzten Schritt bereinigen Sie den Code und wandeln ihn in ein nutzbares Script um.

12. *Letzter Schritt: Refaktorieren

(optional) Es ist gut, wenn die App funktioniert. Gibt es aber Möglichkeiten, sie zu verbessern? Ja, insbesondere die Hauptanwendung, die wie ein durcheinandergewürfeltes Chaos aussieht. Lassen Sie uns das in eine eigene Funktion einfügen und die Eingabe von Nutzern anstelle von festen Konstanten ermöglichen. Dazu verwenden wir das Modul argparse. Außerdem soll ein Webbrowser-Tab geöffnet werden, um das Tabellenblatt anzuzeigen, sobald wir die Datenzeile darin geschrieben haben. Das ist mit dem Modul webbrowser möglich. Fügen Sie diese Importe in die anderen ein, sodass die obersten Importe so aussehen:

from __future__ import print_function
import argparse
import base64
import io
import webbrowser

Damit wir diesen Code in anderen Anwendungen verwenden können, müssen wir die Ausgabe unterdrücken können. Dazu fügen wir ein DEBUG-Flag hinzu. Fügen Sie dazu diese Zeile am Ende des Konstantenteils oben ein:

DEBUG = False

Kommen wir nun zum Hauptteil. Beim Erstellen dieses Beispiels sollten Sie sich langsam „unwohl“ fühlen, da unser Code mit jedem hinzugefügten Dienst eine weitere Verschachtelungsebene hinzufügt. Wenn Sie das Gefühl hatten, dass das der Fall ist, sind Sie nicht allein. Wie in diesem Blogpost im Google Testing Blog beschrieben, erhöht das die Komplexität des Codes.

Wenn wir dieser Best Practice folgen, organisieren wir den Hauptteil der App in einer Funktion und return an jedem „Haltepunkt“ anstelle von Verschachtelung (Rückgabe von None, wenn ein Schritt fehlschlägt, und True, wenn alle erfolgreich sind):

def main(fname, bucket, sheet_id, folder, top, debug):
    '"main()" drives process from image download through report generation'

    # download img file & info from Drive
    rsp = drive_get_img(fname)
    if not rsp:
        return
    fname, mtype, ftime, data = rsp
    if debug:
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

    # upload file to GCS
    gcsname = '%s/%s'% (folder, fname)
    rsp = gcs_blob_upload(gcsname, bucket, data, mtype)
    if not rsp:
        return
    if debug:
        print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

    # process w/Vision
    rsp = vision_label_img(base64.b64encode(data).decode('utf-8'))
    if not rsp:
        return
    if debug:
        print('Top %d labels from Vision API: %s' % (top, rsp))

    # push results to Sheet, get cells-saved count
    fsize = k_ize(len(data))
    row = [folder,
            '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
            bucket, gcsname, fname), mtype, ftime, fsize, rsp
    ]
    rsp = sheet_append_row(sheet_id, row)
    if not rsp:
        return
    if debug:
        print('Added %d cells to Google Sheet' % rsp)
    return True

Das Ergebnis ist übersichtlicher und sauberer. Das Gefühl einer rekursiven if-else-Kette wird vermieden und die Codekomplexität wird wie oben beschrieben reduziert. Das letzte Puzzleteil ist die Erstellung eines „echten“ Haupttreibers, der eine Anpassung durch den Nutzer ermöglicht und die Ausgabe minimiert (sofern nicht anders gewünscht):

if __name__ == '__main__':
    # args: [-hv] [-i imgfile] [-b bucket] [-f folder] [-s Sheet ID] [-t top labels]
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--imgfile", action="store_true",
            default=FILE, help="image file filename")
    parser.add_argument("-b", "--bucket_id", action="store_true",
            default=BUCKET, help="Google Cloud Storage bucket name")
    parser.add_argument("-f", "--folder", action="store_true",
            default=PARENT, help="Google Cloud Storage image folder")
    parser.add_argument("-s", "--sheet_id", action="store_true",
            default=SHEET, help="Google Sheet Drive file ID (44-char str)")
    parser.add_argument("-t", "--viz_top", action="store_true",
            default=TOP, help="return top N (default %d) Vision API labels" % TOP)
    parser.add_argument("-v", "--verbose", action="store_true",
            default=DEBUG, help="verbose display output")
    args = parser.parse_args()

    print('Processing file %r... please wait' % args.imgfile)
    rsp = main(args.imgfile, args.bucket_id,
            args.sheet_id, args.folder, args.viz_top, args.verbose)
    if rsp:
        sheet_url = 'https://docs.google.com/spreadsheets/d/%s/edit' % args.sheet_id
        print('DONE: opening web browser to it, or see %s' % sheet_url)
        webbrowser.open(sheet_url, new=1, autoraise=True)
    else:
        print('ERROR: could not process %r' % args.imgfile)

Wenn alle Schritte erfolgreich sind, wird im Script ein Webbrowser für die angegebene Tabelle geöffnet, in der die neue Datenzeile hinzugefügt wurde.

Zusammenfassung

Sie müssen storage.json nicht löschen, da keine Änderungen am Umfang vorgenommen wurden. Wenn Sie die aktualisierte Anwendung noch einmal ausführen, wird ein neues Browserfenster mit dem geänderten Tabellenblatt geöffnet. Es werden weniger Zeilen ausgegeben. Wenn Sie die Option -h eingeben, werden die Optionen angezeigt, einschließlich -v, um die zuvor unterdrückten Ausgabezellen wiederherzustellen:

$ python3 analyze_gsimg.py
Processing file 'section-work-card-img_2x.jpg'... please wait
DONE: opening web browser to it, or see https://docs.google.com/spreadsheets/d/SHEET_ID/edit

$ python3 analyze_gsimg.py -h
usage: analyze_gsimg.py [-h] [-i] [-t] [-f] [-b] [-s] [-v]

optional arguments:
  -h, --help       show this help message and exit
  -i, --imgfile    image file filename
  -t, --viz_top    return top N (default 5) Vision API labels
  -f, --folder     Google Cloud Storage image folder
  -b, --bucket_id  Google Cloud Storage bucket name
  -s, --sheet_id   Google Sheet Drive file ID (44-char str)
  -v, --verbose    verbose display output

Mit den anderen Optionen können Nutzer verschiedene Drive-Dateinamen, Cloud Storage-„Unterverzeichnisse“ und Bucket-Namen, die „N“ besten Ergebnisse aus Cloud Vision und Tabellen-Datei-IDs (Sheets) auswählen. Nach diesen letzten Updates sollte die endgültige Version Ihres Codes mit dem übereinstimmen, was sich im Repository unterfinal/analyze_gsimg.py befindet, sowie mit dem folgenden Code:

'''
analyze_gsimg.py - analyze Google Workspace image processing workflow

Download image from Google Drive, archive to Google Cloud Storage, send
to Google Cloud Vision for processing, add results row to Google Sheet.
'''

from __future__ import print_function
import argparse
import base64
import io
import webbrowser

from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools

k_ize = lambda b: '%6.2fK' % (b/1000.) # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
PARENT = ''     # YOUR IMG FILE PREFIX
SHEET = 'YOUR_SHEET_ID'
TOP = 5       # TOP # of VISION LABELS TO SAVE
DEBUG = False

# process credentials for OAuth2 tokens
SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
    'https://www.googleapis.com/auth/spreadsheets',
)
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
    creds = tools.run_flow(flow, store)

# create API service endpoints
HTTP = creds.authorize(Http())
DRIVE  = discovery.build('drive',   'v3', http=HTTP)
GCS    = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision',  'v1', http=HTTP)
SHEETS = discovery.build('sheets',  'v4', http=HTTP)


def drive_get_img(fname):
    'download file from Drive and return file info & binary if found'

    # search for file on Google Drive
    rsp = DRIVE.files().list(q="name='%s'" % fname,
            fields='files(id,name,mimeType,modifiedTime)'
    ).execute().get('files', [])

    # download binary & return file info if found, else return None
    if rsp:
        target = rsp[0]  # use first matching file
        fileId = target['id']
        fname = target['name']
        mtype = target['mimeType']
        binary = DRIVE.files().get_media(fileId=fileId).execute()
        return fname, mtype, target['modifiedTime'], binary


def gcs_blob_upload(fname, bucket, media, mimetype):
    'upload an object to a Google Cloud Storage bucket'

    # build blob metadata and upload via GCS API
    body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype}
    return GCS.objects().insert(bucket=bucket, body=body,
            media_body=http.MediaIoBaseUpload(io.BytesIO(media), mimetype),
            fields='bucket,name').execute()


def vision_label_img(img, top):
    'send image to Vision API for label annotation'

    # build image metadata and call Vision API to process
    body = {'requests': [{
                'image':     {'content': img},
                'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}],
    }]}
    rsp = VISION.images().annotate(body=body).execute().get('responses', [{}])[0]

    # return top labels for image as CSV for Sheet (row)
    if 'labelAnnotations' in rsp:
        return ', '.join('(%.2f%%) %s' % (
                label['score']*100., label['description']) \
                for label in rsp['labelAnnotations'])


def sheet_append_row(sheet, row):
    'append row to a Google Sheet, return #cells added'

    # call Sheets API to write row to Sheet (via its ID)
    rsp = SHEETS.spreadsheets().values().append(
            spreadsheetId=sheet, range='Sheet1',
            valueInputOption='USER_ENTERED', body={'values': [row]}
    ).execute()
    if rsp:
        return rsp.get('updates').get('updatedCells')


def main(fname, bucket, sheet_id, folder, top, debug):
    '"main()" drives process from image download through report generation'

    # download img file & info from Drive
    rsp = drive_get_img(fname)
    if not rsp:
        return
    fname, mtype, ftime, data = rsp
    if debug:
        print('Downloaded %r (%s, %s, size: %d)' % (fname, mtype, ftime, len(data)))

    # upload file to GCS
    gcsname = '%s/%s'% (folder, fname)
    rsp = gcs_blob_upload(gcsname, bucket, data, mtype)
    if not rsp:
        return
    if debug:
        print('Uploaded %r to GCS bucket %r' % (rsp['name'], rsp['bucket']))

    # process w/Vision
    rsp = vision_label_img(base64.b64encode(data).decode('utf-8'), top)
    if not rsp:
        return
    if debug:
        print('Top %d labels from Vision API: %s' % (top, rsp))

    # push results to Sheet, get cells-saved count
    fsize = k_ize(len(data))
    row = [folder,
            '=HYPERLINK("storage.cloud.google.com/%s/%s", "%s")' % (
            bucket, gcsname, fname), mtype, ftime, fsize, rsp
    ]
    rsp = sheet_append_row(sheet_id, row)
    if not rsp:
        return
    if debug:
        print('Added %d cells to Google Sheet' % rsp)
    return True


if __name__ == '__main__':
    # args: [-hv] [-i imgfile] [-b bucket] [-f folder] [-s Sheet ID] [-t top labels]
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--imgfile", action="store_true",
            default=FILE, help="image file filename")
    parser.add_argument("-b", "--bucket_id", action="store_true",
            default=BUCKET, help="Google Cloud Storage bucket name")
    parser.add_argument("-f", "--folder", action="store_true",
            default=PARENT, help="Google Cloud Storage image folder")
    parser.add_argument("-s", "--sheet_id", action="store_true",
            default=SHEET, help="Google Sheet Drive file ID (44-char str)")
    parser.add_argument("-t", "--viz_top", action="store_true",
            default=TOP, help="return top N (default %d) Vision API labels" % TOP)
    parser.add_argument("-v", "--verbose", action="store_true",
            default=DEBUG, help="verbose display output")
    args = parser.parse_args()

    print('Processing file %r... please wait' % args.imgfile)
    rsp = main(args.imgfile, args.bucket_id,
            args.sheet_id, args.folder, args.viz_top, args.verbose)
    if rsp:
        sheet_url = 'https://docs.google.com/spreadsheets/d/%s/edit' % args.sheet_id
        print('DONE: opening web browser to it, or see %s' % sheet_url)
        webbrowser.open(sheet_url, new=1, autoraise=True)
    else:
        print('ERROR: could not process %r' % args.imgfile)

Wir werden versuchen, den Inhalt dieses Tutorials auf dem neuesten Stand zu halten. Es kann jedoch vorkommen, dass das Repository die aktuelle Version des Codes enthält.

13. Glückwunsch!

In diesem Codelab gab es viel zu lernen und Sie haben es geschafft, eines der längeren Codelabs zu absolvieren. So haben Sie ein mögliches Unternehmensszenario mit etwa 130 Zeilen Python-Code bewältigt, indem Sie alle Google Cloud- und Google Workspace-Produkte genutzt und Daten zwischen ihnen verschoben haben, um eine funktionierende Lösung zu entwickeln. Im Open-Source-Repository finden Sie alle Versionen dieser App. Weitere Informationen finden Sie unten.

Bereinigen

  1. Die Nutzung von Google Cloud APIs ist nicht kostenlos, während Google Workspace APIs durch Ihre monatliche Google Workspace-Abogebühr abgedeckt sind (für private Gmail-Nutzer fällt eine monatliche Gebühr von null an). Daher ist für Google Workspace-Nutzer keine API-Bereinigung oder ‑Deaktivierung erforderlich. Für Google Cloud können Sie das Cloud Console-Dashboard aufrufen und auf der Abrechnungskarte die geschätzten Kosten einsehen.
  2. Für Cloud Vision ist eine bestimmte Anzahl von API-Aufrufen pro Monat kostenlos zulässig. Solange Sie diese Limits nicht überschreiten, müssen Sie nichts herunterfahren und Ihr Projekt auch nicht deaktivieren oder löschen. Weitere Informationen zur Abrechnung und zum kostenlosen Kontingent der Vision API finden Sie auf der Preisseite.
  3. Einige Cloud Storage-Nutzer erhalten monatlich eine bestimmte Menge an kostenlosem Speicherplatz. Wenn Sie durch die Bilder, die Sie mit diesem Codelab archivieren, das Kontingent nicht überschreiten, fallen keine Gebühren an. Weitere Informationen zur GCS-Abrechnung und zum kostenlosen Kontingent finden Sie auf der Preisseite. Sie können Blobs im Cloud Storage-Browser aufrufen und ganz einfach löschen.
  4. Für die Nutzung von Google Drive gilt möglicherweise auch ein Speicherkontingent. Wenn Sie dieses überschreiten oder fast erreicht haben, können Sie die Bilder mit dem in diesem Codelab erstellten Tool in Cloud Storage archivieren, um mehr Speicherplatz in Drive zu erhalten. Weitere Informationen zum Google Drive-Speicherplatz finden Sie auf der entsprechenden Preisseite für Google Workspace Basic-Nutzer oder Gmail-/Consumer-Nutzer.

Die meisten Google Workspace Business- und Enterprise-Abos bieten unbegrenzten Speicherplatz. Das kann jedoch dazu führen, dass Ihre Drive-Ordner unübersichtlich werden. Die App, die Sie in diesem Tutorial erstellen, ist eine gute Möglichkeit, überflüssige Dateien zu archivieren und Google Drive aufzuräumen.

Alternative Versionen

final/analyze_gsimg.py ist zwar die „letzte“ offizielle Version, an der Sie in dieser Anleitung arbeiten, aber das ist noch nicht alles. Ein Problem mit der endgültigen Version der App besteht darin, dass sie die älteren Authentifizierungsbibliotheken verwendet, die eingestellt wurden. Wir haben uns für diesen Ansatz entschieden, weil die neueren Auth-Bibliotheken zum Zeitpunkt der Erstellung dieses Dokuments mehrere wichtige Elemente nicht unterstützten: die Verwaltung des OAuth-Tokenspeichers und die Threadsicherheit.

Aktuelle (neuere) Authentifizierungsbibliotheken

Die älteren Auth-Bibliotheken werden jedoch irgendwann nicht mehr unterstützt. Wir empfehlen Ihnen daher, sich Versionen anzusehen, die die neueren (aktuellen) Auth-Bibliotheken im Ordner alt des Repositorys verwenden, auch wenn sie nicht threadsicher sind. Sie können jedoch eine eigene Lösung erstellen, die threadsicher ist. Suchen Sie nach Dateien, deren Namen *newauth* enthalten.

Clientbibliotheken für Google Cloud-Produkte

Google Cloud empfiehlt allen Entwicklern, die Produkt-Clientbibliotheken zu verwenden, wenn sie Google Cloud APIs nutzen. Für APIs, die nicht zu Google Cloud gehören, sind solche Bibliotheken derzeit leider nicht verfügbar. Die Verwendung der Bibliotheken auf niedrigerer Ebene ermöglicht eine einheitliche API-Nutzung und bietet eine bessere Lesbarkeit. Ähnlich wie bei der Empfehlung oben sind alternative Versionen mit Google Cloud-Produktclientbibliotheken im Ordner alt des Repositorys verfügbar. Suchen Sie nach Dateien, deren Namen *-gcp* enthalten.

Autorisierung über ein Dienstkonto

Wenn Sie ausschließlich in der Cloud arbeiten, gibt es in der Regel keine Personen oder Daten, die von (menschlichen) Nutzern stammen. Daher werden Dienstkonten und die Dienstkontoautorisierung hauptsächlich in Google Cloud verwendet. Google Workspace-Dokumente gehören jedoch in der Regel Nutzern (Menschen). Daher wird in dieser Anleitung die Autorisierung von Nutzerkonten verwendet. Das bedeutet jedoch nicht, dass es nicht möglich ist, Google Workspace-APIs mit Dienstkonten zu verwenden. Solange diese Konten die entsprechende Zugriffsebene haben, können sie in Anwendungen verwendet werden. Ähnlich wie oben sind alternative Versionen mit Dienstkontoautorisierung im alt-Ordner des Repositorys verfügbar. Suchen Sie nach Dateien, deren Namen *-svc* enthalten.

Katalog alternativer Versionen

Unten finden Sie alle alternativen Versionen von final/analyze_gsimg.py, die jeweils eine oder mehrere der oben genannten Eigenschaften aufweisen. Suchen Sie im Dateinamen jeder Version nach:

  • oldauth“ für Versionen, die die älteren Auth-Bibliotheken verwenden (zusätzlich zu final/analyze_gsimg.py)
  • newauth“ für Nutzer der aktuellen/neueren Authentifizierungsbibliotheken
  • gcp“ für Nutzer von Google Cloud-Produktclientbibliotheken wie „google-cloud-storage“ usw.
  • svc“ für Nutzer, die die Dienstkonto-Authentifizierung („svc acct“) anstelle eines Nutzerkontos verwenden

Hier sind alle Versionen:

Dateiname

Beschreibung

final/analyze_gsimg.py

Das primäre Beispiel verwendet die älteren Authentifizierungsbibliotheken.

alt/analyze_gsimg-newauth.py

Wie final/analyze_gsimg.py, aber mit den neueren Authentifizierungsbibliotheken

alt/analyze_gsimg-oldauth-gcp.py

Wie final/analyze_gsimg.py, aber mit den Google Cloud-Produktclientbibliotheken

alt/analyze_gsimg-newauth-gcp.py

Wie alt/analyze_gsimg-newauth.py, aber mit den Google Cloud-Produktclientbibliotheken

alt/analyze_gsimg-oldauth-svc.py

Wie final/analyze_gsimg.py, verwendet aber ein Dienstkonto anstelle eines Nutzerkontos.

alt/analyze_gsimg-newauth-svc.py

Entspricht alt/analyze_gsimg-newauth.py, verwendet aber die Authentifizierung per Dienstkonto anstelle der Authentifizierung per Nutzerkonto.

alt/analyze_gsimg-oldauth-svc-gcp.py

Wie alt/analyze_gsimg-oldauth-svc.py, aber es werden die Google Cloud-Produktclientbibliotheken verwendet. Wie alt/analyze_gsimg-oldauth-gcp.py, aber es wird die Dienstkontoauthentifizierung anstelle der Nutzerkontoauthentifizierung verwendet.

alt/analyze_gsimg-newauth-svc-gcp.py

Wie alt/analyze_gsimg-oldauth-svc-gcp.py, aber mit den neueren Authentifizierungsbibliotheken

Zusammen mit dem ursprünglichen final/analyze_gsimg.py haben Sie alle möglichen Kombinationen der endgültigen Lösung , unabhängig von Ihrer Google API-Entwicklungsumgebung, und können diejenige auswählen, die Ihren Anforderungen am besten entspricht. Eine ähnliche Erklärung finden Sie auch unter alt/README.md.

Zusätzliche Informationen

Hier sind einige Ideen, wie Sie diese Übung noch weiter ausbauen können. Der Problembereich, den die aktuelle Lösung abdecken kann, kann erweitert werden, sodass Sie die folgenden Verbesserungen vornehmen können:

  1. Mehrere Bilder in Ordnern: Anstatt ein einzelnes Bild zu verarbeiten, haben Sie beispielsweise Bilder in Google Drive-Ordnern.
  2. (Mehrere Bilder in ZIP-Dateien) Anstelle eines Ordners mit Bildern können Sie auch ZIP-Archive mit Bilddateien verwenden. Wenn Sie Python verwenden, sollten Sie das zipfile-Modul in Betracht ziehen.
  3. Vision-Labels analysieren: Gruppieren Sie ähnliche Bilder. Suchen Sie zuerst nach den häufigsten Labels, dann nach den zweithäufigsten usw.
  4. Diagramme erstellen: Folgeanfrage 3, Diagramme mit der Sheets API erstellen basierend auf der Vision API-Analyse und ‑Kategorisierung
  5. Dokumente kategorisieren: Anstatt Bilder mit der Cloud Vision API zu analysieren, haben Sie beispielsweise PDF-Dateien, die Sie mit der Cloud Natural Language API kategorisieren möchten. Mit den oben genannten Lösungen können sich diese PDFs in Drive-Ordnern oder ZIP-Archiven in Drive befinden.
  6. Präsentationen erstellen: Mit der Google Slides API können Sie eine Präsentation aus dem Inhalt des Google-Tabellenberichts generieren. In diesem Blogpost und Video finden Sie Anregungen zum Generieren von Folien aus Tabellendaten.
  7. Als PDF exportieren: Die Tabelle und/oder Präsentation wird als PDF exportiert. Dies ist jedoch keine Funktion der Sheets API oder der Slides API. Hinweis: Google Drive API. Zusatzaufgabe: Führen Sie die beiden PDFs aus Sheets und Präsentationen mit Tools wie Ghostscript (Linux, Windows) oder Combine PDF Pages.action (Mac OS X) zu einem Master-PDF zusammen.

Weitere Informationen

Codelabs

Allgemein

Google Workspace

Google Cloud

Lizenz

Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.