フィーチャ サービス/フィーチャクラスから添付ファイル (アタッチメント) を一括でダウンロードするサンプル ツールを作成しました!

1582
0
04-29-2021 11:41 PM
Labels (1)

フィーチャ サービス/フィーチャクラスから添付ファイル (アタッチメント) を一括でダウンロードするサンプル ツールを作成しました!

はじめに

ArcGIS Pro では、アタッチメント (添付ファイル: 画像、PDF、テキスト文書、その他すべての種類のファイル) フィーチャクラスの各フィーチャに追加することができ、またエクスポートしてローカルに保存することもできます。なお、エクスポートは 1 つのフィーチャに対してのみしか行うことができません。

そこで、今回はフィーチャクラスのすべてのフィーチャから添付ファイルを一括でエクスポートするツールを ArcPy を使用して作成しました。

さらに、ArcGIS API for Python を組み合わせることで、ArcGIS Online に公開しているホスト フィーチャ サービスに対しても同様に、添付ファイルを一括でエクスポートできます。

ツールは下記からダウンロードしていただけます。 

toolbox_scripttool.png

tooldialog.png

今回は、さらに Python スクリプトをオリジナルのジオプロセシング ツールとして使用できるスクリプト ツールも作成しています。スクリプト ツールとして作成しておくことで、Python のコーディングに不慣れな方もオリジナルの機能を ArcGIS Pro UI からジオプロセシング ツールとして利用していただくことができます。

ツールは下記の記事を参考に作成しています。

 

使用している製品

  • ArcGIS Pro 2.7.3 (Basic ライセンス)
  • ArcGIS API for Python 1.8.3

 

処理の流れ

  1. モジュールのインポート
  2. パラメーターの設定
  3. ArcGIS Online にアクセス
  4. データを分割するための OBJECTID のリストを取得
  5. レプリカを作成する際の条件式を作成
  6. フィーチャ サービスからファイル ジオデータベースのレプリカを作成しローカルにダウンロード
  7. ダウンロードしたレプリカ (ZIP ファイル) からアタッチメント テーブルを取得
  8. アタッチメント テーブルから添付ファイルを抽出

 

各処理のコード

1. モジュールのインポート

実行に必要なモジュールをインポートします。ArcPy モジュール (arcpy) ArcGIS API for Python モジュール (arcgis.features など) をインポートして Python から GIS の機能にアクセスします。

import arcpy 
import arcgis.features
import arcgis.features.managers
import arcgis.gis
import os
import zipfile
from datetime import datetime

 

2. パラメータの設定

arcpy.GetParameterAsText() 関数を使用してスクリプト ツールの実行に必要なパラメーターを設定します。

agol_flag = arcpy.GetParameterAsText(0)
user_name = arcpy.GetParameterAsText(1)
password = arcpy.GetParameterAsText(2)
feature_service_url = arcpy.GetParameterAsText(3)
replica_layers = arcpy.GetParameterAsText(4)
attachment_table = arcpy.GetParameterAsText(5)
dtime = datetime.now().strftime("%Y%m%d%H%M%S")
replica_name = "replica_%s" % (dtime)
output_folder = os.path.join(arcpy.GetParameterAsText(6), replica_name)

 

3. ArcGIS Online にアクセス

ArcGIS API for Python の arcgis.gis.GIS クラスを使用して ArcGIS Online にアクセスします。

def AccessAgol(user_name, password):
gis = arcgis.gis.GIS("https://www.arcgis.com", user_name, password)
return gis

 

4. データを分割するための OBJECTID のリストを取得

大量のデータに対して一度にレプリカを作成できないため、データを最大 5,000 レコードずつに分割するための OBJECTID のリストを取得します。
※ツールの実行に失敗する場合は、分割するレコード数を小さく設定して試してください

def SplitObjectIds(object_ids):
    n = 5000
    sort_object_ids = sorted(object_ids)
    for i in range(0, len(sort_object_ids), n):
        yield sort_object_ids[i:i + n]

 

5. レプリカを作成する際の条件式を作成

OBJECTID のリストをもとに、レコードを分割して処理するための条件式を作成します。

def CreateWheres(replica_layers, feature_layer_collection):
    # フィーチャ サービスの各レイヤーに対して処理
    for id in replica_layers.split(","):
        for feature_layer in feature_layer_collection.layers:
            if feature_layer.url[-1] == id:
                query = feature_layer.query(where='1=1', return_ids_only=True)
                # レコードを分割して処理するための条件式を作成
                split_object_ids = SplitObjectIds(query["objectIds"])
                for object_ids in split_object_ids:
                    sql_Where = "{'%s': {'where':'(OBJECTID >= %d AND OBJECTID <= %d)' , 'useGeometry' : false}}" %(id, object_ids[0], object_ids[-1])
                    yield sql_Where

 

6. フィーチャ サービスからファイル ジオデータベースのレプリカを作成しローカルにダウンロード

条件式をもとに、ArcGIS API for Python arcgis.features.FeatureLayerCollection クラスarcgis.features.managers.SyncManage.create() 関数を使用してホスト フィーチャ サービスからファイル ジオデータベースのレプリカを作成し、指定したフォルダーにダウンロードします。
※レプリカの作成にはフィーチャ サービスの同期とエクスポート機能が有効化されている必要があります

def CreateReplicaAndDownroad(feature_service_url, gis, replica_name, replica_layers, output_folder):
    # 処理対象のフィーチャ サービスを取得
    feature_layer_collection = arcgis.features.FeatureLayerCollection(feature_service_url, gis)
    # フィーチャ サービスがレプリカの作成に対応しているかチェック
    if "Extract" in feature_layer_collection.properties.capabilities and "Sync" in feature_layer_collection.properties.capabilities:
        # 指定したフォルダーが存在しない場合は作成
        if os.path.exists(output_folder) == False:
            os.mkdir(output_folder)
        # 条件式ごとにレプリカを作成
        layer_queries = CreateWheres(replica_layers, feature_layer_collection)
        for layer_query in layer_queries:
            replica = feature_layer_collection.replicas.create(replica_name=replica_name,
                                                            layers=replica_layers,
                                                             layer_queries=layer_query,
                                                             return_attachments=True,
                                                             return_attachments_databy_url=False,
                                                             asynchronous=True,
                                                             attachments_sync_direction="bidirectional",
                                                             sync_model="none",
                                                             data_format="filegdb",
                                                             wait=True,
                                                             out_path=output_folder)
            yield replica
    else:
        arcpy.AddError("> 対象のフィーチャ サービスがレプリカの作成に対応していません。フィーチャ サービスの同期とエクスポート機能を有効化して再度試してください。")

 

7. ダウンロードしたレプリカ (ZIP ファイル) からアタッチメント テーブルを取得

ArcPy の arcpy.da.Walk() 関数を使用して、指定したフォルダーからアタッチメント テーブルを取得します。

def GetAttachmentTable(zip_file):
    # ZIP ファイルを解凍
    extract_path = os.path.splitext(zip_file)[0]
    with zipfile.ZipFile(zip_file) as z:
        z.extractall(extract_path)
    os.remove(zip_file)
    # 解凍したファイルからアタッチメント テーブルを取得
    walk = arcpy.da.Walk(extract_path, topdown=True, datatype="FeatureClass")
    for dirpath, dirnames, filenames in walk:
        for filename in filenames:
            attachment_table = "%s__ATTACH" %(os.path.join(dirpath, filename))
            return attachment_table

 

8. アタッチメント テーブルから添付ファイルを抽出

ArcPy の arcpy.da.SearchCursor クラスを使用して、アタッチメント テーブルの各レコードにアクセスし格納されている添付ファイルを指定したフォルダーに抽出します。

def ExportAttachments(attachment_tables, dtime, output_folder):
    for attachment_table in attachment_tables:
        # 入力テーブルからパスを取得して、ワークスペースを設定
        workspace_path = os.path.dirname(attachment_table)
        arcpy.env.workspace = workspace_path
        # 入力テーブルから、テーブル結合に使用するための結合先となるテーブルを取得
        input_table_name = os.path.basename(attachment_table)
        join_featureclass_name = input_table_name.split("__")[0]
        # テーブル結合を行うためのデータを作成
        input_table_view = arcpy.MakeTableView_management(attachment_table, "inTableView_%s" %(dtime))
        join_feature_layer = arcpy.MakeFeatureLayer_management(join_featureclass_name, "featureLayer_%s" % (dtime))
        # アタッチメント テーブルの GUID フィールド名を取得
        for view_field in arcpy.ListFields(input_table_view):
            if view_field.type.lower() == "guid":
                guid_field_name = view_field.name
                break
        # フィーチャクラスの Global ID フィールド名を取得
        for field in arcpy.ListFields(join_feature_layer):
            if field.type.lower() == "globalid":
                globalid_field_name = field.name
            elif field.type.lower() == "oid":
                oid_field_name = field.name
        # テーブル結合の実行
        join_layer = arcpy.AddJoin_management(
                        input_table_view, guid_field_name, join_feature_layer, globalid_field_name, "KEEP_ALL")
        # 結合テーブルから添付ファイルを抽出して出力
        with arcpy.da.SearchCursor(join_layer,
                                ["%s.DATA" %(input_table_name),
                                    "%s.ATT_NAME" %(input_table_name),
                                    "%s.%s" %(join_featureclass_name, oid_field_name)]) as cursor:
            for row in cursor:
                binaryRep = row[0]
                fileName = row[1]
                OID = row[2]
                open("%s//%s_%s" %(output_folder, OID, fileName), "wb").write(binaryRep)
                del row
                del binaryRep
                del fileName
                arcpy.Delete_management(join_layer)
                arcpy.Delete_management(input_table_view)
                arcpy.Delete_management(join_feature_layer)

 

最後に

Python を使用することで、ArcGIS 上で地理空間データを操作する便利なプログラムを開発することができ、今回のように添付ファイルを一括でエクスポートするなど、作業の効率化が図れます。また、Web GIS (ArcGIS Online / ArcGIS Enterprise) に共有しているデータは、様々なユーザーがアクセスして、参照・編集が可能なため、ArcGIS Pro の機能を扱う ArcPy と、Web GISの機能を扱う ArcGIS API for Python を組み合わせることで、Web GIS に共有しているデータに対して効率的に作業を行うことができ、よりデータを有効活用することができます。

 

参考

Labels (1)
Version history
Revision #:
2 of 2
Last update:
‎08-18-2021 06:31 PM
Updated by:
 
Contributors