Často se setkávám s dotazy ohledně stahování příloh (např. obrázků a dokumentů) z ArcGIS Online Feature Layers. Cílem tohoto je poskytnout alternativní řešení k tomu, co je aktuálně k dispozici.<\/P>
<\/P>
Za prvé, jediný způsob, jak jsou přílohy zahrnuty při exportu dat přes ArcGIS Online, je export jako File Geodatabase. Důvodem je, že File Geodatabase je jediný formát, který podporuje související záznamy. Proto je nejčastější odpovědí na přístup k přílohám Feature Layer mimo ArcGIS Online exportovat Feature Layer jako File Geodatabase a extrahovat data pomocí skriptu jako je tento<\/A> prostřednictvím ArcGIS Desktop. K dispozici je také sync script<\/A> , který může synchronizovat lokální File Geodatabase s hostovaným Feature Layer. Tyto metody fungují dobře, ale spoléhají na ArcGIS Desktop a v případě první možnosti také vyžadují před spuštěním skriptu stáhnout File Geodatabase (která může růst velikostí s přidáváním dat).<\/P><\/P>Z tohoto důvodu jsem vytvořil skript využívající nový ArcGIS API for Python<\/A> , který funguje nezávisle na ArcGIS Desktop. Ve skutečnosti pracuje přímo s Web GIS, takže nemusíte ani stahovat File Geodatabase, abyste získali přístup ke svým přílohám. Skript lze spouštět pravidelně a stahuje pouze nové přílohy na disk, pokud je ještě nebyly dříve staženy.<\/P><\/P>Co tento skript dělá?<\/STRONG><\/P><\/P>Vytvoří složku, ve které jsou uloženy přílohy feature (např. Attachment Downloads)<\/LI>Uvnitř této složky vytvoří podsložku pro každou vrstvu ve specifikovaném Feature LayerPokud je proměnná AttachmentStorage nastavena na 'GroupedFolder<\/SPAN>', přílohy jsou uloženy ve formátu ObjectId-AttachmentId-OriginalFileName v jedné složce<\/LI>Pokud je proměnná AttachmentStorage nastavena na 'IndividualFolder', vytvoří se nová složka pro každý prvek s přílohou (pojmenovaná podle Object ID prvku), zatímco přílohy jsou uloženy ve formátu AttachmentId-OriginalFileName uvnitř této složky<\/LI><\/OL><\/LI>Pokud příloha již existuje na disku, nebude znovu stažena<\/LI>Souhrn stažení (celkový počet stažení a celková velikost příloh) je uveden jako závěrečný výstup v konzoli<\/LI><\/OL><\/P>Jak se nastavit?<\/STRONG><\/P><\/P>Postupujte podle průvodce ArcGIS API for Python <A href="https:\/\/developers.arcgis.com\/python\/guide\/install-and-set-up\/\
Z tohoto důvodu jsem vytvořil skript využívající nový
Co tento skript dělá?<\/STRONG><\/P><\/P>Vytvoří složku, ve které jsou uloženy přílohy feature (např. Attachment Downloads)<\/LI>Uvnitř této složky vytvoří podsložku pro každou vrstvu ve specifikovaném Feature LayerPokud je proměnná AttachmentStorage nastavena na 'GroupedFolder<\/SPAN>', přílohy jsou uloženy ve formátu ObjectId-AttachmentId-OriginalFileName v jedné složce<\/LI>Pokud je proměnná AttachmentStorage nastavena na 'IndividualFolder', vytvoří se nová složka pro každý prvek s přílohou (pojmenovaná podle Object ID prvku), zatímco přílohy jsou uloženy ve formátu AttachmentId-OriginalFileName uvnitř této složky<\/LI><\/OL><\/LI>Pokud příloha již existuje na disku, nebude znovu stažena<\/LI>Souhrn stažení (celkový počet stažení a celková velikost příloh) je uveden jako závěrečný výstup v konzoli<\/LI><\/OL><\/P>Jak se nastavit?<\/STRONG><\/P><\/P>Postupujte podle průvodce ArcGIS API for Python <A href="https:\/\/developers.arcgis.com\/python\/guide\/install-and-set-up\/\
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
Přihlášení členové mohou přispívat, sledovat aktualizace a další. Nový zde? Zaregistrujte si bezplatný účet.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.