Ik ben vaak vragen tegengekomen over het downloaden van bijlagen (bijv. foto's en documenten) van ArcGIS Online Feature Layers. Het doel hiervan is om een alternatieve oplossing te bieden voor wat momenteel beschikbaar is.<\/P>
<\/P>
Ten eerste is de enige manier waarop bijlagen worden opgenomen bij het exporteren van gegevens via ArcGIS Online, wanneer geëxporteerd wordt als een File Geodatabase. De reden hiervoor is dat de File Geodatabase het enige formaat is dat gerelateerde records ondersteunt. Daarom is het meest voorkomende antwoord om toegang te krijgen tot Feature Layer-bijlagen buiten ArcGIS Online, om de Feature Layer te exporteren als een File Geodatabase en de gegevens uit te extruderen met een script zoals dit<\/A> via ArcGIS Desktop. Er is ook een sync script<\/A> beschikbaar dat een lokale File Geodatabase kan synchroniseren met een gehoste Feature Layer. Deze werken goed, maar ze zijn afhankelijk van ArcGIS Desktop, en in het geval van optie één, moet je ook de File Geodatabase (die in grootte kan toenemen naarmate je er meer gegevens aan toevoegt) vooraf downloaden voordat je het script uitvoert.<\/P><\/P>Om deze reden heb ik een script gemaakt met behulp van de nieuwe ArcGIS API for Python<\/A> dat onafhankelijk werkt van ArcGIS Desktop. In feite werkt het direct met een Web GIS, dus je hoeft niet eens een File Geodatabase te downloaden om toegang te krijgen tot je bijlagen. Het kan regelmatig opnieuw worden uitgevoerd en downloadt alleen nieuwe bijlagen naar de schijf als deze nog niet eerder zijn gedownload.<\/P><\/P>Wat doet dit script precies?<\/STRONG><\/P><\/P>Maakt een map aan waarin feature-bijlagen worden opgeslagen (bijv. Attachment Downloads)<\/LI>Maakt binnen deze map een submap voor elke laag in de opgegeven Feature LayerAls de AttachmentStorage-variabele is ingesteld op 'GroupedFolder<\/SPAN>', worden bijlagen opgeslagen in het formaat ObjectId-AttachmentId-OriginalFileName in één enkele map<\/LI>Als de AttachmentStorage-variabele is ingesteld op 'IndividualFolder', wordt er voor elke feature met een bijlage een nieuwe map gemaakt (genoemd naar de Object ID van de feature), terwijl de bijlagen worden opgeslagen in het formaat AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Als de bijlage al op de schijf bestaat, wordt deze niet opnieuw gedownload<\/LI>Samenvatting van downloads (totaal aantal downloads en totale grootte van bijlagen) wordt als laatste console-uitvoer weergegeven<\/LI><\/OL><\/P>Hoe stel je dit in?<\/STRONG><\/P><\/P>Volg de ArcGIS API for Python Installatie- en setupgids<\/A>Als je Anaconda gebruikt, kun je het .yml-bestand gebruiken om de juiste omgeving te creëren<\/LI><\/OL><\/LI>Als je het Startup.bat-bestand gebruikt, bewerk dit dan (in een teksteditor) om naar de juiste mappen te verwijzen<\/LI>Zodra je een Jupyter Notebook hebt geopend, plak je het bijgevoegde .zip-bestand hieronder op een toegankelijke locatie (en pak je het uit)<\/LI>Open het bestand DownloadAttachments.ipynb via Jupyter Notebooks en voer het uit (klik in de code en druk op Ctrl+Enter)<\/LI>Het script wordt uitgevoerd op de opgegeven openbare Feature Layer en downloadt de bijlagen naar de opgegeven Downloads-map<\/LI>Elke keer dat je het script uitvoert, wordt er een bijbehorend logbestand aangemaakt in de Logging-map<\/LI><\/OL><\/P>Aantekeningen:<\/STRONG><\/P><\/P>Werk de FeatureLayerId-variabele<\/SPAN> bij om het op je eigen Feature Layer uit te voeren<\/LI>Specificeer je PortalUserName, PortalPassword als de Feature Layer beveiligd is<\/LI>De namen van mappen worden gefilterd zodat alleen 0-9 en a-Z tekens worden weergegeven<\/LI>Dit script is niet getest met ArcGIS Enterprise (alleen Feature Layers gehost in ArcGIS Online), maar zou nog steeds moeten werken<\/LI>Code ook beschikbaar via de Esri developer-support GitHub repository<\/A><\/LI><\/UL><\/BODY><\/HTML>
Om deze reden heb ik een script gemaakt met behulp van de nieuwe
Wat doet dit script precies?<\/STRONG><\/P><\/P>Maakt een map aan waarin feature-bijlagen worden opgeslagen (bijv. Attachment Downloads)<\/LI>Maakt binnen deze map een submap voor elke laag in de opgegeven Feature LayerAls de AttachmentStorage-variabele is ingesteld op 'GroupedFolder<\/SPAN>', worden bijlagen opgeslagen in het formaat ObjectId-AttachmentId-OriginalFileName in één enkele map<\/LI>Als de AttachmentStorage-variabele is ingesteld op 'IndividualFolder', wordt er voor elke feature met een bijlage een nieuwe map gemaakt (genoemd naar de Object ID van de feature), terwijl de bijlagen worden opgeslagen in het formaat AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Als de bijlage al op de schijf bestaat, wordt deze niet opnieuw gedownload<\/LI>Samenvatting van downloads (totaal aantal downloads en totale grootte van bijlagen) wordt als laatste console-uitvoer weergegeven<\/LI><\/OL><\/P>Hoe stel je dit in?<\/STRONG><\/P><\/P>Volg de ArcGIS API for Python
Aantekeningen:<\/STRONG><\/P><\/P>Werk de FeatureLayerId-variabele<\/SPAN> bij om het op je eigen Feature Layer uit te voeren<\/LI>Specificeer je PortalUserName, PortalPassword als de Feature Layer beveiligd is<\/LI>De namen van mappen worden gefilterd zodat alleen 0-9 en a-Z tekens worden weergegeven<\/LI>Dit script is niet getest met ArcGIS Enterprise (alleen Feature Layers gehost in ArcGIS Online), maar zou nog steeds moeten werken<\/LI>Code ook beschikbaar via de
Hi Holly - have you ever got this script working before? I have not replicated this behaviour with the version of the Python API included with ArcGIS Pro 2.1.2 (v1.2.5). Can you test with the FeatureLayerId = '092d075f4b3a40f78cf1329b20b0d5e7' - this is a public layer so you should be able to access.
I initially wrote this using v1.2.0 of the ArcGIS API for Python - I have not tested it with later versions.
Hi Michael, thanks for this post...very useful!
I am trying to download a feature layer created by a Survey123 application that allows users to capture multiple photos per record. To do so we had to build it as a relationship. Here is the URL: https:[host]/portal/home/item.html?id=f0dcf24f2bb9440d9fa2c8ec64141fe1#data. When viewing the Data tab from the Portal I can select the "(0) Add" text in the "Photos and Files" field to access the photos. I tried plugging f0dcf24f2bb9440d9fa2c8ec64141fe1#data into the FeatureLayerID =, but it returns no files. Any idea what I may be missing?
Hi Eric,
If the photos are stored in a table with no spatial attributes, it will appear as a table through the API (as opposed to a layer). Therefore the 'layers' text in lines 81/82/96 have to be chanced to 'tables'.
<SPAN class="comment token">#Lines 81/82</SPAN> <SPAN class="keyword token">for</SPAN> i <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>itemObject<SPAN class="punctuation token">.</SPAN>tables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN> featureLayer <SPAN class="operator token">=</SPAN> itemObject<SPAN class="punctuation token">.</SPAN>tables<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="comment token">#Line 96</SPAN> logger<SPAN class="punctuation token">.</SPAN>info<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'Currently looping through feature attachments in layer {} of {}: storing in folder named "{}"'</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>str<SPAN class="punctuation token">(</SPAN>i <SPAN class="operator token">+</SPAN> <SPAN class="number token">1</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> str<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>itemObject<SPAN class="punctuation token">.</SPAN>tables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> featureLayerName<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
This should loop through any associated tables (as opposed to layers) and return the appropriate results.
Kind regards,
Mikie
That was exactly what I needed! Thanks so much!
Hey Mike,
The script is running as expected, but I am trying to get it to place the attachments in a folder named after a value specified by a specific field ("Subject") in the related layer. Do you have any pointers for how to configure that?
Thanks!
Eric
Hi Eric - a similar question came through in one of the comments above. You would have to alter the query to send back the appropriate attributes, and then use the returned attributes whilst specifying the associated file name.
I can't carry out this program because the following error happens. Please tell me the solution.
My feature layer comprises Japanese words. So this error may happen.
Is this program applicable to Japanese layers?
File "C:\ProgramData\Anaconda3\lib\http\client.py", line 1117, in putrequest self._output(request.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 43-45: ordinal not in range(128)
Hi Holly,
I was getting the same error as you. I fixed it by adding [0] to the end of the currentAttachmentPath variable so that it gets the first and only attachment path in that list and uses it. I had to add it to this part: renameFile(currentAttachmentPath[0], newAttachmentPath) under both GroupedFolder and IndividualFolder. I tested it on Michael's public layer, and was able to download the attachments.
Thank you very much.
I'll try it.
2018年7月6日(金) 3:08 Chelsea Rozek <geonet@esri.com>:
GeoNet <https://community.esri.com/?et=watches.email.document_comment>Downloading Feature Layer Attachments via the ArcGIS API for Pythonnew comment by Chelsea Rozek<https://community.esri.com/people/rozekc_washtenaw?et=watches.email.document_comment> Viewall comments on this document<https://community.esri.com/docs/DOC-10441-downloading-feature-layer-attachments?commentID=63017&et=watches.email.document_comment#comment-63017>
GeoNet <https://community.esri.com/?et=watches.email.document_comment>
Downloading Feature Layer Attachments via the ArcGIS API for Python
new comment by Chelsea Rozek
<https://community.esri.com/people/rozekc_washtenaw?et=watches.email.document_comment> View
all comments on this document
<https://community.esri.com/docs/DOC-10441-downloading-feature-layer-attachments?commentID=63017&et=watches.email.document_comment#comment-63017>
Hi 竹元 貴彦,
Did you get the script working with the pre-set public layer? I have not tested this against layers with Japanese. Does the layer itself (layer name, field names, etc.) contain Japanese, or is there Japanese only in the attributes? Is the layer available publically, or could you share it with me through a group? My ArcGIS Online username is mikie.kelly.
Mikie,
This is an awesome script and I was able to get it working quickly despite limited Python experience. I am wondering how line 92 might be modified to fetch GUIDs instead of OIDs.
I worked using private layer. So I can't show it imediately. I make or search another layer that contains Japanese to show you the problem as soon as possible.
My private layer has Japanese both field name and attributes.
Hi Bob,
Global ID's are returned with the attachments. You can access them by adding to lines 108-111 as below (both attachment Global ID and attachment parent Global ID accessible):
<SPAN class="keyword token">for</SPAN> k <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>currentObjectIdAttachments<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN> attachmentGlobalId <SPAN class="operator token">=</SPAN> currentObjectIdAttachments<SPAN class="punctuation token">[</SPAN>k<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="string token">'globalId'</SPAN><SPAN class="punctuation token">]</SPAN> attachmentParentGlobalId <SPAN class="operator token">=</SPAN> currentObjectIdAttachments<SPAN class="punctuation token">[</SPAN>k<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="string token">'parentGlobalId'</SPAN><SPAN class="punctuation token">]</SPAN> attachmentId <SPAN class="operator token">=</SPAN> currentObjectIdAttachments<SPAN class="punctuation token">[</SPAN>k<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="string token">'id'</SPAN><SPAN class="punctuation token">]</SPAN> attachmentName <SPAN class="operator token">=</SPAN> currentObjectIdAttachments<SPAN class="punctuation token">[</SPAN>k<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">]</SPAN> attachmentSize <SPAN class="operator token">=</SPAN> currentObjectIdAttachments<SPAN class="punctuation token">[</SPAN>k<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="string token">'size'</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
Then you can reference them when naming the file 117
fileName = '{}-{}-{}'.format(attachmentGlobalId, attachmentParentGlobalId, attachmentName)<SPAN class="line-numbers-rows"><SPAN></SPAN></SPAN>
Works like a charm. Thanks.
Great script. I would also appreciate having the attachment files named based on a field in the associated attribute table. You mentioned this is possible but would require some rejigging -- have you or anyone else developed script for this?
Annalise
Hi Annalise,
I'm afraid not, at least not that I'm aware of.
I work with the U.S. Fish and Wildlife Service and use an Enterprise Account login. Can this script function with an Enterprise login?
#What are your ArcGIS Enterprise/ArcGIS credentials? This is case sensitive.PortalUserName = 'email here'PortalPassword = 'password here'PortalUrl = 'https://fws.maps.arcgis.com'
I changed the PortalURL to direct to the FWS ArcGIS URL but I keep getting an error message -- [ERROR:arcgis._impl.connection:Invalid username or password.]
I've confirmed that the username and password I entered are correct.
https://fws.maps.arcgis.com is an address for ArcGIS as opposed to ArcGIS Enterprise. All ArcGIS accounts can simply use https://www.arcgis.com for the PortalUrl. An ArcGIS Enterprise address is likely to look like this: https://portalcomputer.domain.com/portal/home.
PortalUserName = 'MKelly@MyDomain'
PortalPassword = 'MyPassword'
PortalUrl = 'https://portalcomputer.domain.com/portal/home'
Further information can be found here. One thing to note is that the username can be case sensitive - you need to replicate how it appears in the Portal organisation page.
Hi Michael
Great script, quick question: Is it possible to get a file-like object from the attachments manager without downloading the file locally first?
So instead of downloading the file with attachments.download i would want to have the attachment as an in-memory object...
Currently my script first downloads the attachment and then opens it into a binary file-like object and then delete the local file when i am done....
Any help will be appreciated.
Hi Deon,
I haven't noticed anything like that in the AttachmentManager class - is there a problem with the approach you are currently taking?
get_list includes the URL of any attachments (from what I remember) if that's any use?
Hi Michael Kelly,
A couple of days ago our machines were upgraded to ArcGIS Pro 2.2.1 (Python 3.6.5).
Since then attachments fail to include "OBJECTID - ATTACHMENTID" in the attachment file names (only attachment names).
Can you think of the reason for this - from the top of your head? Otherwise, I'm more than happy to take a further look.
But I thought I'd ask you first.
Thanks,
Gee
All sorted.
It was the same error as what Holly Tran was experiencing. And managed to get it working by using Chelsea Rozek's suggestion.
Thanks guys,
Getting this error with enterprise. Anyone have a possible solution?
Sounds like Holly's error above, see my previous response for a solution: adding [0] to the end of the currentAttachmentPath variable
I did that step and this error popped up.
Is the feature layer you're running this on publicly accessible? If yes, what's the url?
this worked for me too (ie just adding [0] on line 123, and line 137, so that the line is
renameFile(currentAttachmentPath[0], newAttachmentPath)
instead of
renameFile(currentAttachmentPath, newAttachmentPath)
- I am running python 3.7.2, so it seems to be an issues that comes up when using a later version of python
Hello Michael Kelly. Thank you fo putting script together and sharing it with the Community. I forked your project in Github. I'm working on adding capabilities the Community is requesting here and will submit a commit soon. Plus I am adding the ability to choose a portal that is Enterprise or AGO, and some other automation.
As for saving each attachment with a file name using an attribute value I am running into an issue with the FeatureSet object that is returned from Query() I am passing in the currentObjectId to obtain the field containing the pole number, which is esupportstructure_facilityid.
currentObjectId <SPAN class="operator token">=</SPAN> featureObjectIds<SPAN class="punctuation token">[</SPAN><SPAN class="string token">'objectIds'</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN> facilityID <SPAN class="operator token">=</SPAN> featureLayer<SPAN class="punctuation token">.</SPAN>query<SPAN class="punctuation token">(</SPAN>objectids<SPAN class="operator token">=</SPAN>currentObjectId<SPAN class="punctuation token">,</SPAN> outFields<SPAN class="operator token">=</SPAN><SPAN class="string token">'esupportstructure_facilityid'</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
The documentation appears to return a JSON object so I also tried treated it as such. When I do that another error appears as attached below,
FeatureSet' object is not subscriptable
I have not found any ArcGIS Python API examples that work with FeatureSet object and Query(), can you point to some samples or provide a snippet.
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-1-bc6c83cbc278> in <module> 202 currentObjectId = featureObjectIds['objectIds'][j] 203 facilityID = featureLayer.query(objectids=currentObjectId, outFields='esupportstructure_facilityid')--> 204 poleNumber = facilityID['eSupportStructure_FACILITYID'] 205 logger.info(f'{poleNumber}') 206 currentObjectIdAttachments = featureLayer.attachments.get_list(oid=currentObjectId)TypeError: 'FeatureSet' object is not subscriptable
JSON Response from Query().
INFO:__main__:{"features": [{"geometry": {"x": 2678790.012921214, "y": 236090.84788563848}, "attributes": {"eSupportStructure_FACILITYID": "47185"}}], "objectIdFieldName": "OBJECTID", "globalIdFieldName": "GlobalID", "spatialReference": {"wkid": 102660, "latestWkid": 2238}, "geometryType": "esriGeometryPoint", "fields": [{"name": "eSupportStructure_FACILITYID", "alias": "Pole Number", "type": "esriFieldTypeString", "length": 20}]}
Michael Kelly Thanks for this script! I'm using it for a few applications and it works great! Recently I implemented a survey123 app that captures pictures in a repeat, and so images are attached to a related table. Can this script be modified to download attachments from related tables, or is does it need to be from the feature layer?
Hi, everybody.I followed the post to download the attached photos from a survey I generated (the photos are inside a table).I have also modified the script because I had the same problem as @Chelsea Rozek
I'm running the script inside the ArcGis Online Notebook.It doesn't give me any error and it seems to download the content. However I go to the path where the downloaded photos are supposed to be but the folder doesn't exist. Although the script is saying that the photos are downloaded.
INFO:__main__:Time: 2020-06-08 10:44:57.796204 INFO:__main__:Currently looping through feature attachments in layer 1 of 2: storing in folder named "0-foto" INFO:__main__:There are 386 features to iterate in this layer INFO:__main__:The size of the current attachment being downloaded is 1.17647MB ----------
INFO:__main__:C:\ScriptDownloads\\0-foto\\103/fotos-20200525-132307.jpg being renamed as C:\ScriptDownloads\\0-foto\\103\103-fotos-20200525-132307.jpg INFO:__main__:The size of the current attachment being downloaded is 1.69949MB
Any suggestions? Thanks
Aangemelde leden kunnen berichten plaatsen, updates volgen en meer. Nieuw hier? Registreer een gratis account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.