Python スクリプトでの Web ツールの使用

Python スクリプトを作成して、Web ツールを複数の方法で実行および利用できます。スクリプトを実行する主な手段は ArcPy の使用です。ArcPy には、サービスからの結果に接続し、実行して処理するメソッドが組み込まれています。代わりに、ArcGIS Server Services Directory からサービスにアクセスすると、組み込みの Python モジュールを使って、JSON 構造を使用した REST 呼び出しを行い、結果を転送することができます。この方法を利用するには、Python コードによってクライアントを最初から構築する必要があります。スクリプトの大部分は、ArcPy を介してジオプロセシング サービスに接続し使用します。

メモ:

ここで示す例では、実際の ArcGIS Server サービスを使用します。ポータルからは Web ツールは使用しません。

ArcPy の使用

Web ツールには、ArcGIS Pro[Python] ウィンドウ、スクリプト ツール、またはスタンドアロン スクリプトを使用してアクセスできます。Web ツールに接続して使用するには URL が使用されます。

ImportToolbox を使用してサービスに接続します。

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

ツールのインポートに使用されるパスは Web ツールの URL です。ImportToolbox は、2 つのパラメーター (サービスへの URL とツールボックスのオプションのエイリアス) を受け入れます。URL パラメーターはセミコロン (;) で 2 つの部分に区切られます。最初の部分はサービス エンド ポイントへの URL (リンク) であり、次の部分はサービス名 (オプションで、サービス名の前にフォルダー名が付加される) です。

Web ツールは同期または非同期のいずれかの方法で実行されます。Python スクリプトを使用するには、ユーザーは、サービスの実行方法を理解している必要があります。サービスの実行方法を判断するには、IsSynchronous プロパティを使用できます。サービスが同期して実行されている場合、結果は自動的に返されますが、サービスが完了するまで他のアクションを行うことはできません。非同期サービスの場合は、現在の実行ステータスを定期的に照会する必要があります。サービスの実行が完了すると、結果へのアクセスが可能になります。

次の Python コードは、非同期ジオプロセシング サービスに接続し、ArcPy 関数を使用してサービスを実行し、結果を取得してその結果をさらに処理する方法を示しています。タスクの実行時に result 変数を設定することで、while ループをステータスの確認に使用できます。タスクは、ステータス コード 4 (succeeded) 以上が返されると終了します。

非同期サービスを使用してバッファーを作成し、結果をローカルに保存します。

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 の使用

Web ツールを使用するもう 1 つの方法 (ただし、使用頻度は少ない) は、データ交換形式として JSON を使用して REST 呼び出しを行うスクリプトの作成です。この方法では、ユーザーが、リクエストの送信と応答の処理の両方についてコードを記述する必要があります。

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 は、Web ブラウザーのアドレス バーで使用できます。

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 コードは、Service Directory を使用するか、リンクを Web ブラウザーのアドレス バーにコピーした場合と同様な方法で上記のリクエストを実行します。

# 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 オブジェクトは文字列として返されます。リクエストの作成と結果の解析に使用できる多数の異なるメソッドが用意されており、上記の例は、メソッドの 1 つを示しています。Web ツールから返される JSON は、上記の例のように json.loads() を使用してディレクトリに配置できます。Web ツールの出力によっては、これが最適な手法であることもあれば、REST を介して Python から利用される出力を処理するために、他のオプションを検討する必要があることもあります。

メモ:

結果のフィーチャを操作するときは、実際の X、Y 座標ペアの使用がワークフローで機能していることを確認してください。この理由は、実際のフィーチャは、ArcGIS でジオメトリをサポートするフォーマットでは受信されないからです。

非同期で実行されるサービスの場合は、ArcPy を使用した上記の例と同様に、定期的にタスクのステータスを要求して、タスクが終了したかどうかを確認する必要があります。Python コードにより、jobStatus ステータス メッセージ内のフレーズ esriJobSucceeded または esriJobFailed を探すことができます。これらのフレーズは、ジョブ ステータスの確認時に返されます。次のサンプル コードは、非同期 Web ツールを操作する手法の 1 つ (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")

関連トピック


このトピックの内容
  1. ArcPy の使用
  2. REST の使用