Python スクリプトを作成して、Web ツールまたはジオプロセシング サービスを複数の方法で実行および使用できます。 スクリプトを実行する主な手段としては ArcPy を使用します。ArcPy には、サービスからの結果に接続し、実行して処理するメソッドが組み込まれています。 また、ArcGIS REST API からサービスにアクセスする場合には、組み込みの Python モジュールで、JSON 構造を使用して REST 呼び出しを行い、結果を転送することもできます。 この方法を利用するには、Python コードによってクライアントを最初から構築する必要があります。 スクリプトの大部分は、ArcPy を介してジオプロセシング サービスに接続し使用します。
注意:
以下に示す例では、フェデレーション ArcGIS Server のジオプロセシング サービスを使用しています。 Python では、ポータルから対応する Web ツール アイテムを使用することはありません。
ArcPy の使用
Web ツールには、ArcGIS Pro の [Python] ウィンドウ、スクリプト ツール、またはスタンドアロン スクリプトを使用してアクセスできます。 ImportToolbox 関数では、サービス URL とその他の値を使用し、Web ツールに接続して使用します。
例: ImportToolbox で SOAP URL、フォルダー内のサービス、ユーザー名とパスワードを使用してサービスに接続します。
arcpy.ImportToolbox("https://organization.example.com/<context>/services;GPFolder/BufferService;serverusername;serverpassword")
Web ツールとジオプロセシング サービスは、同期または非同期のどちらでも実行できます。 Python スクリプトの作成者は、サービスを使用するために、そのサービスの実行方法を理解しておく必要があります。 IsSynchronous プロパティを使用して、サービスを同期または非同期のどちらで実行するかを指定できます。 サービスが同期して実行されている場合、結果は自動的に返されますが、サービスが完了するまで他のアクションを行うことはできません。 サービスが非同期で実行されている場合、現在のステータスを定期的に照会する必要があります。 サービスの実行が完了したら、その結果にアクセスできます。
次の Python コードは、非同期ジオプロセシング サービスに接続する方法を示しています。 このコードでは、ArcPy 関数を使用して、サービスを実行し、結果を取得して、その結果をさらに処理します。 タスクの実行時に result 変数を設定することで、while ループを Result オブジェクトのステータスのチェックに使用できます。 タスクは、ステータス コード 4 (succeeded) 以上が返されると終了します。
非同期サービスを使用してバッファーを作成し、結果をローカルに保存します。
import arcpy
import time
arcpy.ImportToolbox("https://organization.example.com/<context>/services;Elevation/viewshedAlias;serverusername;serverpassword")
result = arcpy.viewshedAlias.Viewshed(r'c:\data.gdb\inputPoint', "10000 Kilometers")
while result.status < 4:
print(result.status)
time.sleep(0.2)
print("Tool finished")
print(result.getMessages())
arcpy.management.CopyFeatures(result, r'c:\results.gdb\result')
REST エンドポイントの使用
Web ツールを使用するもう 1 つの方法は、JSON をデータ交換形式として使用して REST 呼び出しを行うスクリプトの作成です。 この方法では、リクエストを送信するコードとレスポンスを処理するコードを記述する必要があります。
REST メッセージの送受信がより深く関与することになり、ユーザーは入出力構文のすべての内容を処理しなければなりません。 REST メッセージを送受信するメリットは、それらのメッセージが一貫した方法で返される点にあります。 リクエストは、HTTP GET または HTTP POST メソッドを介して送信し、レスポンスは、JSON として構造化して返すことができます。
次の例では、リクエストを送信し、レスポンスを処理する方法を示しています。
リクエストの送信
たとえば、可視領域を作成するジオプロセシング サービスには https://organization.example.com/<context>/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 ブラウザーのアドレス バーで使用できます。
https://organization.example.com/<context>/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 ブラウザーのアドレス バーにコピーした場合と同様な方法で上記のリクエストを実行します。
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://organization.example.com/<context>/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 座標ペアの使用がワークフローで機能していることを確認してください。この理由として、実際のフィーチャは、ArcPy でジオメトリをサポートしているフォーマットでは受信されないからです。
非同期で実行されるサービスの場合は、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 = "https://organization.example.com/<context>/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")