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 zum Service herzustellen, diesen auszuführen und das Ergebnis zu verarbeiten. Sie können aber auch über das ArcGIS-Server-Services-Verzeichnis auf integrierte Python-Module zugreifen, 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.

Hinweis:

In den Beispielen hier wird der eigentliche ArcGIS Server-Service verwendet. Der Geoverarbeitungsservice wird nicht über das Portal verwendet.

Verwenden von ArcPy

Sie können über das Fenster Python 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 eine Verbindung mit einem Service her.

# arcpy.ImportToolbox("http://<hostname>:<port>/arcgis/services;<optional folder>/<service name>", "<optional alias>")
arcpy.ImportToolbox("https://degrassi/arcgis/services;GPFolder/BufferService", "PointAlias")

Der Pfad zum Importieren des Werkzeugs ist die URL des Geoverarbeitungsservice. ImportToolbox akzeptiert zwei Parameter: die URL zum Service und einen optionalen Aliasnamen für die Toolbox. Der URL-Parameter ist in zwei Teile unterteilt, die mit Strichpunkt getrennt werden (;). Der erste Teil ist die URL (oder der Link) zum Service-Endpunkt, und der zweite Teil ist der Name des Service (optional steht vor dem Servicenamen ein Ordnername).

Ein Geoverarbeitungsservice kann entweder synchron oder asynchron ausgeführt werden. Als jemand, der Python-Skripte erstellt, müssen Sie verstehen, wie der Service ausgeführt wird, um ihn zu verwenden. Die Eigenschaft IsSynchronous kann verwendet werden, um den Ausführungstyp eines Service zu bestimmen. 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. Bei asynchronen Services muss der aktuelle Status der Ausführung regelmäßig abgefragt werden. Wenn die Ausführung des Service abgeschlossen ist, kann auf das Ergebnis zugegriffen werden.

Der folgende Python-Code zeigt, wie eine Verbindung zu 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://sampleserver6.arcgisonline.com/ArcGIS/services;Elevation/ESRI_Elevation_World", "viewshedAlias")
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 Resultobjekt und zu Statuscodes sowie zum Erstellen von Raster- und Kartenbildausgaben finden Sie im Hilfethema Verwenden von Werkzeugen in Python.

REST verwenden

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 Analysieren von JSON-Meldungen erleichtern.

Das folgende Beispiel verwendet einen Service auf den Esri Beispielservern und zeigt, wie Sie eine Verbindung zum Service herstellen, eine Anforderung senden und eine Antwort verarbeiten würden.

Senden der Anforderung

SampleServer6 enthält beispielsweise einen Geoverarbeitungsservice zur Erstellung von Sichtfeldern und ist über http://sampleserver6.arcgisonline.com/ArcGIS/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.

http://sampleserver6.arcgisonline.com/ArcGIS/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 wenn das Service-Verzeichnis verwendet oder der Link in die Adressleiste eines Webbrowsers kopiert wird.

# 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 = 'http://sampleserver6.arcgisonline.com/ArcGIS/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 Resultobjekt wird als Zeichenfolge zurückgegeben. Es gibt mehrere Methoden, um eine Anforderung zu erstellen und ein Ergebnis zu analysieren; 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 XY-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 esriJobSucceeded nach dem Ausdruck esriJobFailed oder jobStatus 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 = "http://localhost:6080/arcgis/rest/services/WorldViewshed/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")