Использование сервисов геообработки в скриптах Python

Можно написать скрипт Python для его запуска и использования сервиса геообработки несколькими способами. Основной способ запуска скрипта – использовать ArcPy. ArcPy имеет встроенные методы для подключения, выполнения и обработки результатов сервиса. Кроме того, если вы получаете доступ к сервису из ArcGIS Server Services Directory, вы можете использовать встроенные модули Python для выполнения вызовов REST с использованием структуры JSON для передачи результатов. Для использования этих возможностей необходимо создать клиент "с нуля" с помощью кода Python. Большинство скриптов подключаются и используют сервисы геообработки через ArcPy.

Примечание:

Приведенные примеры используют фактический сервис ArcGIS Server. Сервис геообработки не используется на портале.

Использование ArcPy

Доступ к сервису геообработки можно получить через окно Python в ArcGIS Pro, через инструмент-скрипт или автономный скрипт. Для подключения и использования сервиса геообработки используется URL-адрес сервиса.

Подключитесь к сервису при помощи ImportToolbox.


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

Путь, используемый для импорта инструмента, является URL-адресом сервиса геообработки. ImportToolbox кроме двух параметров: URL к сервису и дополнительный псевдоним для набора инструментов. Параметр URL-адреса разделяется на две части с использованием точки с запятой (;). Первая часть — это URL-адрес (или ссылка) конечной точки, а вторая — имя сервиса (дополнительно; имя папки предшествует имени сервиса).

Сервис геообработки может выполняться синхронно или асинхронно. Создатель сценариев Python должен понимать, как выполняется сервис, чтобы эффективно его использовать. Свойство IsSynchronous можно задействовать для определения типа выполнения сервиса. Если сервис выполняется синхронно, результат возвращается автоматически, но, до завершения работы инструмента нельзя предпринимать никаких действий. При использовании асинхронных сервисов, следует периодически опрашивать текущий статус выполнения. После выполнения сервиса можно получить доступ к результатам.

В следующем коде Python показано, как подключиться к асинхронному сервису геообработки и, задействуя функции ArcPy, получить результаты и обработать их. При настройке переменной результата во время выполнения задачи можно настроить цикл while для проверки статуса. Задача завершается после возвращения кода состояния 4 (успешно) или выше.

Используйте асинхронный сервис для создания буфера и локального сохранения результатов.

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')

Дополнительные сведения об объекте Result и кодах состояния, а также создании выходных растровых и картографических изображений доступны в разделе справки Использование инструментов в Python.

Использование REST

Альтернативным (но менее распространенным) способом использования сервиса геообработки является написание скрипта, осуществляющего вызовы REST, с использованием JSON в качестве формата обмена данными. При использовании этого метода необходимо написать код как для отправки запроса, так и для обработки ответа.

Отправка и получение сообщений REST требует большего участия разработчика, так как следует самостоятельно обрабатывать все аспекты синтаксиса для входных и выходных объектов. При отправке и получении сообщений REST они возвращаются в согласованном порядке. Запрос может быть послан с помощью метода HTTP GET или HTTP POST, а ответ вернется структурированным как JSON. Ключевые библиотеки Python поддерживают и отправку запроса, и функции, которые упрощают чтение и обработку сообщений JSON.

В приведенном ниже примере используется сервис на приведенных в качестве примера серверах Esri и демонстрируется, как следует подключаться к сервису, отправлять запрос и обрабатывать ответ.

Отправка запроса

К примеру, SampleServer6 содержит сервис геообработки для создания областей видимости. Доступ к нему осуществляется через http://sampleserver6.arcgisonline.com/ArcGIS/rest/services/Elevation. Этот сервис берет в качестве входных данных точку и расстояние, а возвращает набор объектов. Следующие входные данные позволят лучше понять сервис:

Имя параметраВходное значение

Входная точка наблюдения (GPFeatureRecordSetLayer)

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

Расстояние области видимости (GPLinearUnit)

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

Формат (формат выходных данных)

JSON

Этот запрос возвращает из сервиса JSON видимые местоположения. В адресной строке веб-браузера можно использовать полный URL-адрес, с помощью которого был создан запрос.

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

URL-адрес может быть предоставлен с помощью модуля Python urllib или urllib2. Следующий код Python приведет к выполнению приведенного выше запроса способом, аналогичным использованию каталога сервиса или копированию ссылки в адресную строку веб-браузера.


# 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')))

Объект Result возвращается в виде строки. Существует ряд методов, которые можно использовать для выполнения запроса и обработки результата; приведенный выше пример — это лишь один из методов. JSON, возвращаемый от сервиса геообработки, может быть размещен в словарь с помощью json.loads(), как показано в предыдущем примере. В зависимости от выходных данных сервиса геообработки, это может быть наилучшим способом, или может понадобиться рассмотреть другие варианты обработки выходных данных при их использовании в Python с применением REST.

Примечание:

При работе с результирующими объектами убедитесь, что использование фактических пар x, y имеет смысл для вашего рабочего процесса, так как фактические объекты не будут получены в формате, поддерживающем геометрию в ArcGIS.

Сервис, который выполняется асинхронно, нуждается в периодическом запросе статуса задачи, чтобы узнать, завершена ли она (аналогично вышеприведенному примеру с использованием ArcPy). Код Python может искать фразу esriJobSucceeded или esriJobFailed в сообщении статуса jobStatus, которое возвращается при проверке статуса задания. В приведенном ниже примере кода демонстрируется один из способов работы с асинхронным сервисом геообработки (с использованием 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")