HOW TO
In the ArcGIS Survey123 website, all survey records or a subset of the survey record data can be exported as a CSV, Microsoft Excel, KML, shapefile, or in a file geodatabase format. However, if the survey data contain image attachments, the survey data must be exported as a file geodatabase and the images extracted manually. Fortunately, this process can be automated using the ArcGIS API for Python Survey123 module. Follow the workflow described in this article to export the Survey123 survey data and attachments using a stand-alone Python file (.py). The Python file also runs in Jupyter Notebook.
import arcgis from arcgis.gis import GIS import os, re, csv
portalURL = "<Portal for ArcGIS or ArcGIS Online URL>" username = "<username>" password = "<password>" survey_item_id = "<ArcGIS Survey123 form item ID>" save_path = r"<survey results and attachments save folder directory>" keep_org_item = <defineTrue
if the exported item is to be added to Content for the ArcGIS organization, orFalse
if otherwise
> store_csv_w_attachments = <define False if the .csv file that maps each attachment to its parent object ID should be stored in the root folder (with the exported Excel workbook), or True, in each individual layer folder>
gis = GIS(portalURL, username, password) survey_by_id = gis.content.get(survey_item_id)
rel_fs = survey_by_id.related_items('Survey2Service','forward')[0] item_excel = rel_fs.export(title=survey_by_id.title, export_format='Excel') item_excel.download(save_path=save_path) if not bool(keep_org_item): item_excel.delete(force=True)
# Define the features to be exported. layers = rel_fs.layers + rel_fs.tables for i in layers: # Identify whether the features has attachments. if i.properties.hasAttachments == True: # Set the export path folder when the features has attachments. feature_layer_folder = os.path.join(save_path, '{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name))) os.mkdir(feature_layer_folder) if bool(store_csv_w_attachments): path = os.path.join(feature_layer_folder, "{}_attachments.csv".format(i.properties.name)) elif not bool(store_csv_w_attachments): path = os.path.join(save_path, "{}_attachments.csv".format(i.properties.name)) csv_fields = ['Parent objectId', 'Attachment path'] with open(path, 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(csv_fields) feature_object_ids = i.query(where="1=1", return_ids_only=True, order_by_fields='objectid ASC') for j in range(len(feature_object_ids['objectIds'])): current_oid = feature_object_ids['objectIds'][j] current_oid_attachments = i.attachments.get_list(oid=current_oid) # Create a new folder for the attachments to be exported and new CSV file using the layer name with the suffix '_attachments' appended to it. The new CSV file contains the parent object ID and the relative folder path for each attachment in the layer. if len(current_oid_attachments) > 0: for k in range(len(current_oid_attachments)): attachment_id = current_oid_attachments[k]['id'] current_attachment_path = i.attachments.download(oid=current_oid, attachment_id=attachment_id, save_path=feature_layer_folder) csvwriter.writerow([current_oid, os.path.join('{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)), os.path.split(current_attachment_path[0])[1])])
print("<message>")
The code block below demonstrates the full working script.
import arcgis from arcgis.gis import GIS import os, re, csv portalURL = "https://www.arcgis.com" username = "Username123" password = "Password123" survey_item_id = "e7ed3bfae65c4cbe8fee28ef38472bd1" save_path = r"C:\Users\ISC-DT27-JASON\Documents\Article work\Article 28397" keep_org_item = False store_csv_w_attachments = False gis = GIS(portalURL, username, password) survey_by_id = gis.content.get(survey_item_id) rel_fs = survey_by_id.related_items('Survey2Service','forward')[0] item_excel = rel_fs.export(title=survey_by_id.title, export_format='Excel') item_excel.download(save_path=save_path) if not bool(keep_org_item): item_excel.delete(force=True) layers = rel_fs.layers + rel_fs.tables for i in layers: if i.properties.hasAttachments == True: feature_layer_folder = os.path.join(save_path, '{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name))) os.mkdir(feature_layer_folder) if bool(store_csv_w_attachments): path = os.path.join(feature_layer_folder, "{}_attachments.csv".format(i.properties.name)) elif not bool(store_csv_w_attachments): path = os.path.join(save_path, "{}_attachments.csv".format(i.properties.name)) csv_fields = ['Parent objectId', 'Attachment path'] with open(path, 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(csv_fields) feature_object_ids = i.query(where="1=1", return_ids_only=True, order_by_fields='objectid ASC') for j in range(len(feature_object_ids['objectIds'])): current_oid = feature_object_ids['objectIds'][j] current_oid_attachments = i.attachments.get_list(oid=current_oid) if len(current_oid_attachments) > 0: for k in range(len(current_oid_attachments)): attachment_id = current_oid_attachments[k]['id'] current_attachment_path = i.attachments.download(oid=current_oid, attachment_id=attachment_id, save_path=feature_layer_folder) csvwriter.writerow([current_oid, os.path.join('{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)), os.path.split(current_attachment_path[0])[1])]) print("Completed")
Get help from ArcGIS experts
Download the Esri Support App