Verwenden von Geoverarbeitungsservices in Python-Skripten

Sie können ein Python-Skript schreiben, um einen Geoverarbeitungsservice auf verschiedene Weise auszuführen und zu verwenden. Die häufigste Methode der Skriptausführung stellt die Verwendung von ArcPy dar. ArcPy verfügt über integrierte Methoden, um eine Verbindung mit dem Service herzustellen, diesen auszuführen und das Ergebnis zu verarbeiten. Wenn Sie über das ArcGIS-Server-Services-Verzeichnis auf den Service zugreifen, können Sie alternativ integrierte Python-Module verwenden, um REST-Aufrufe mit einer JSON-Struktur zur Übermittlung von Ergebnissen durchzuführen. Um diese Methode zu verwenden, müssen Sie einen Client mit Python-Code von Grund auf neu erstellen. Die meisten Skripte verwenden ArcPy zum Verbinden mit und Verwenden von Geoverarbeitungsservices.

Verwenden von ArcPy

Sie können über das Python-Fenster in ArcGIS Pro, ein Skriptwerkzeug oder ein eigenständiges Skript auf einen Geoverarbeitungsservice zugreifen. Die Service-URL dient zum Verbinden mit und Verwenden von Geoverarbeitungsservices.

Stellen Sie mit ImportToolbox oder AddToolbox eine Verbindung mit einem Service her.

# arcpy.ImportToolbox("https://machine.domain.com/webadaptor/services;<optional folder>/<service name>;{username};{password}")
arcpy.ImportToolbox("https://machine.domain.com/webadaptor/services;GPFolder/BufferService;serverusername;serverpassword")

Der Pfad zum Importieren des Werkzeugs ist die URL des Web-Werkzeugs. ImportToolbox and AddToolbox übernimmt die Informationen des Servers, die aus vier durch ein Semikolon (;) getrennten Teilen bestehen. Der erste Teil ist die URL (oder der Link) zum Service-Endpunkt, der zweite Teil ist der Name des Service (optional steht vor dem Servicenamen ein Ordnername), der dritte ist der optionale Benutzername für den Server, und der letzte ist das optionale Kennwort für den Server. Geben Sie den Benutzernamen und das Kennwort an, wenn Sie nicht über die Berechtigung für den Zugriff auf das Web-Werkzeug verfügen.

Ein Geoverarbeitungsservice kann entweder synchron oder asynchron ausgeführt werden. Wenn Sie Python-Skripte erstellen, müssen Sie verstehen, wie der Service ausgeführt wird, um ihn zu verwenden. Mit der Eigenschaft IsSynchronous kann festgelegt werden, ob der Service synchron oder asynchron ausgeführt wird. Wenn ein Service synchron ausgeführt wird, werden die Ergebnisse automatisch zurückgegeben, aber es können erst nach Abschluss des Service Aktionen durchgeführt werden. Wenn ein Service asynchron ausgeführt wird, muss der aktuelle Status regelmäßig abgefragt werden. Wenn die Ausführung des Service abgeschlossen ist, können Sie auf das Ergebnis zugreifen.

Der folgende Python-Code zeigt, wie eine Verbindung mit einem asynchronen Geoverarbeitungsservice hergestellt wird. Darüber hinaus wird demonstriert, wie dieser mithilfe von ArcPy-Funktionen ausgeführt wird, wie die Ergebnisse abgerufen werden und wie diese weiter verarbeitet werden. Wenn Sie beim Ausführen des Tasks eine Ergebnisvariable festlegen, kann der Status mithilfe einer while-Schleife überprüft werden. Der Task ist abgeschlossen, wenn der Statuscode 4 (erfolgreich) oder höher ausgegeben wird.

Verwenden Sie einen asynchronen Service, um einen Puffer zu erstellen und das Ergebnis lokal zu speichern.

import arcpy
import time

arcpy.ImportToolbox("http://machine.domain.com/webadaptor/services;Elevation/viewshedAlias;serverusername;serverpassword")

result = arcpy.Viewshed_viewshedAlias(r'c:\data\inputPoint.shp', "10000 Kilometers")

while result.status < 4:
	   print(result.status)
	   time.sleep(0.2)
print("Execution Finished")

print(result.getMessages())
arcpy.CopyFeatures_management(result[0], 'localResult.shp')

Weitere Informationen zum Result-Objekt und zu Statuscodes sowie zum Erstellen von Raster- und Kartenbildausgaben finden Sie im Hilfethema Verwenden von Werkzeugen in Python.

Verwenden von REST

Eine andere (weniger gängige) Methode zur Verwendung eines Geoverarbeitungsservice ist das Schreiben eines Skripts, das REST-Aufrufe ausführt. Als Datenaustauschformat wird JSON verwendet. Bei dieser Methode müssen Sie sowohl zum Senden der Anforderung als auch zum Verarbeiten der Antwort Code schreiben.

Das Senden und Empfangen von REST-Meldungen ist komplizierter, da Sie für sämtliche Aspekte der Syntax der Ein- und Ausgaben selbst zuständig sind. Wenn REST-Meldungen gesendet und empfangen werden, werden sie kontinuierlich zurückgegeben. Eine Anfrage kann über eine HTTP-GET- oder HTTP-POST-Methode gesendet werden, und eine Antwort kann als JSON strukturiert zurückkommen. Die zentralen Python-Bibliotheken unterstützen das Senden einer Anforderung sowie Funktionen, die das Lesen und Parsen von JSON-Meldungen erleichtern.

Das folgende Beispiel zeigt, wie Sie eine Verbindung mit dem Service herstellen, eine Anforderung senden und eine Antwort verarbeiten würden.

Senden der Anforderung

Ein Geoverarbeitungsservice zum Erstellen von Sichtfeldern beispielsweise ist über https://machine.domain.com/webadaptor/rest/services/Elevation erreichbar. Dieser Service verwendet einen Punkt und eine Entfernung als Eingabe und gibt ein Feature-Set zurück. Mit den folgenden Eingaben kann der Service besser verstanden werden:

ParameternameEingabewert

Input Observation Point (GPFeatureRecordSetLayer)

{"geometryType" : "esriGeometryPoint", "spatialReference" : {"wkid" : 54003}, 'features':[{'geometry':{'x': -13308192.1956127, 'y': 4221903.58555983}}]}

Viewshed Distance (GPLinearUnit)

{ 'distance' : 8.5, 'units' : 'esriMiles' }

Format (Format der Ausgabe)

JSON

Diese Anforderung gibt den JSON-Code der vom Service aus sichtbaren Positionen zurück. Die vollständige URL, die zur Erstellung der Anforderung verwendet wird, kann in der Adressleiste eines Webbrowers verwendet werden.

https://machine.domain.com/webadaptor/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed/execute?Input_Observation_Point={%22features%22%3A[{%22geometry%22%3A{%22x%22%3A-13308192.1956127%2C%22y%22%3A4221903.58555983}}]}&Viewshed_Distance={+%27distance%27+%3A+8.5%2C+%27units%27+%3A+%27esriMiles%27+}&env%3AoutSR=&env%3AprocessSR=&f=pjson

Die URL kann mithilfe des Python-Moduls urllib oder urllib2 gesendet werden. Der folgende Python-Code würde die obige Anforderung ähnlich ausführen wie bei Verwendung des Services-Verzeichnisses oder beim Kopieren des Links in die Adressleiste eines Webbrowsers.

# Requires Python 3+
import urllib.request as urlopen
import urllib.parse as urlencode
import urllib.request as request
import json

inPts = {"geometryType" : "esriGeometryPoint",
         "spatialReference" : {"wkid" : 54003},
         'features':[{'geometry': {'x': -13308192.1956127, 'y': 4221903.58555983}}]}
dist = {'distance':8.5,'units':'esriMiles'}

data = {'Input_Observation_Point': inPts,
        'Viewshed_Distance': dist,
        'f': 'pjson'}

URL = 'https://machine.domain.com/webadaptor/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed/execute'

req = request.Request(URL, urlencode.urlencode(data).encode('UTF-8'))
response = urlopen.urlopen(req)
response_bytes = response.read()
print(json.loads(response_bytes.decode('UTF-8')))

Das Result-Objekt wird als Zeichenfolge zurückgegeben. Sie können verschiedene Methoden verwenden, um eine Anforderung zu erstellen und ein Ergebnis zu parsen; das obige Beispiel stellt nur eine dieser Methoden dar. Der von einem Geoverarbeitungsservice zurückgegebene JSON-Code kann mithilfe von json.loads() in einem Wörterbuch abgelegt werden, wie im vorherigen Beispiel gezeigt. Je nach der Ausgabe des Geoverarbeitungsservice kann dies die beste Methode sein. Möglicherweise müssen Sie aber andere Optionen prüfen, um die Ausgabe bei Verwendung in Python über REST zu verarbeiten.

Hinweis:

Achten Sie beim Arbeiten mit Ergebnis-Features darauf, dass es für Ihren Workflow sinnvoll ist, die tatsächlichen x,y-Paare zu verwenden, da Sie die eigentlichen Features nicht in einem Format erhalten, das Geometrien in ArcGIS unterstützt.

Bei einem asynchronen Service müssen Sie, ähnlich wie beim obigen Beispiel bei Verwendung von ArcPy, regelmäßig den Status eines Tasks abfragen, um zu sehen, ob der Task beendet ist. Ihr Python-Code könnte in der Statusmeldung jobStatus nach dem Ausdruck esriJobSucceeded oder esriJobFailed suchen, der beim Überprüfen des Auftragsstatus zurückgegeben wird. Das folgende Codebeispiel zeigt eine Technik für das Arbeiten mit einem asynchronen Geoverarbeitungsservice (unter Verwendung von submitJob).

import urllib.request as urlopen
import urllib.parse as urlencode
import urllib.request as request
import json
import time

def sendReq(URL, data=None):

    req = request.Request(URL, urlencode.urlencode(data).encode('UTF-8'))
    response = urlopen.urlopen(req)
    response_bytes = response.read()
    return json.loads(response_bytes.decode('UTF-8'))

inPts = {"geometryType": "esriGeometryPoint",
         "spatialReference": {"wkid" : 54003},
         'features': [{'geometry': {'x': -13308192.1956127, 'y': 4221903.58555983}}]}
dist = {'distance': 8.5, 'units': 'esriMiles'}

data = {'Input_Observation_Point': inPts,
        'Viewshed_Distance': dist,
        'f': 'pjson'}

taskUrl = "https://machine.domain.com/webadaptor/rest/services/Elevation/GPServer/viewshed"
submitUrl = taskUrl + "/submitJob"

submitJson = sendReq(submitUrl, data)

if 'jobId' in submitJson:
    jobID = submitJson['jobId']
    status = submitJson['jobStatus']
    jobUrl = taskUrl + "/jobs/" + jobID

    while status == "esriJobSubmitted" or status == "esriJobExecuting":
        print("checking to see if job is completed...")
        time.sleep(1)

        jobJson = sendReq(jobUrl, {"f": "json"})

        if 'jobStatus' in jobJson.keys():
            status = jobJson['jobStatus']

            if status == "esriJobSucceeded":
                if 'results' in jobJson:
                    resultsJson = jobJson['results']
                    for paramName in resultsJson.keys():
                        resultsUrl = jobUrl + "/" + resultsJson[paramName]['paramUrl']
                        resultJson = sendReq(resultsUrl, {"f": "json"})
                        print(resultJson)

            if status == "esriJobFailed":
                if 'messages' in jobJson.keys():
                    print(jobJson['messages'])

else:
    print("no jobId found in the response")