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

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

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

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

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

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

Путём для импорта инструмента является URL веб-инструмента. ImportToolbox and AddToolbox принимает информацию от сервера, которая включает четыре части, разделенных точкой с запятой (;). Первая часть – это URL-адрес (или ссылка) конечной точки, а вторая – имя сервиса (дополнительн имя папки предшествует имени сервиса), третья - дополнительно имя пользователя сервера, и четвертая - дополнительно пароль сервера. Укажите имя пользователя и пароль, если у вас нет прав на доступ к веб-инструменту.

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

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

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

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

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

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

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

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

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

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

К примеру, сервис геообработки для создания областей видимости доступен по ссылке https://machine.domain.com/webadaptor/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-адрес, с помощью которого был создан запрос.

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

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

Объект 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 = "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")