He encontrado comúnmente preguntas sobre la descarga de archivos adjuntos (por ejemplo, imágenes y documentos) de Feature Layers de ArcGIS Online. El objetivo de esto es proporcionar una solución alternativa a lo que se ofrece actualmente.<\/P>
<\/P>
En primer lugar, la única forma en que los archivos adjuntos se incluyen al exportar datos a través de ArcGIS Online es cuando se exporta como un File Geodatabase. La razón de esto es que el File Geodatabase es el único formato que soporta registros relacionados. Por lo tanto, la respuesta más común para acceder a los archivos adjuntos de Feature Layer fuera de ArcGIS Online es exportar el Feature Layer como un File Geodatabase, y extraer los datos usando un script como este<\/A> a través de ArcGIS Desktop. También hay un script de sincronización<\/A> disponible que puede sincronizar un File Geodatabase local con un Feature Layer alojado. Estos funcionan bien, pero dependen de ArcGIS Desktop, y en el caso de la primera opción, también requieren que descargues el File Geodatabase (que puede crecer en tamaño a medida que agregas datos) antes de ejecutar el script.<\/P><\/P>Por esta razón, creé un script usando el nuevo ArcGIS API for Python<\/A> que funciona independientemente de ArcGIS Desktop. De hecho, funciona directamente con un Web GIS, por lo que ni siquiera tienes que descargar un File Geodatabase para acceder a tus archivos adjuntos. Puede ejecutarse regularmente y solo descarga nuevos archivos adjuntos al disco si no han sido descargados previamente.<\/P><\/P>¿Qué hace este script?<\/STRONG><\/P><\/P>Crea una carpeta en la que se almacenan los archivos adjuntos del feature (por ejemplo, Descargas de Archivos Adjuntos)<\/LI>Dentro de esta carpeta crea una subcarpeta para cada capa en el Feature Layer especificadoSi la variable AttachmentStorage está configurada como 'GroupedFolder<\/SPAN>', los archivos adjuntos se almacenan en el formato ObjectId-AttachmentId-OriginalFileName en una sola carpeta<\/LI>Si la variable AttachmentStorage está configurada como 'IndividualFolder', se crea una nueva carpeta para cada feature con un archivo adjunto (nombrada usando el Object ID del feature), mientras que los archivos adjuntos se almacenan dentro en el formato AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Si el archivo adjunto ya existe en disco no se descargará nuevamente<\/LI>Resumen de descargas (número total de descargas y tamaño total de los archivos adjuntos) proporcionado como salida final en consola<\/LI><\/OL><\/P>¿Cómo configurarlo?<\/STRONG><\/P><\/P>Sigue la guía Instalar y configurar del ArcGIS API for Python<\/A>Si usas Anaconda, puedes usar el archivo .yml para crear el entorno apropiado<\/LI><\/OL><\/LI>Si usas el archivo Startup.bat, edítalo (en un editor de texto) para referenciar las carpetas adecuadas<\/LI>Una vez que tengas abierto un Jupyter Notebook, pega el archivo .zip adjunto abajo en una ubicación accesible (y descomprímelo)<\/LI>Abre el archivo DownloadAttachments.ipynb vía Jupyter Notebooks y ejecútalo (haz clic dentro del código y presiona Ctrl+Enter)<\/LI>El script se ejecutará sobre un Feature Layer público especificado y descargará los archivos adjuntos a la carpeta Downloads especificada<\/LI>Se crea un archivo log asociado en la carpeta Logging cada vez que ejecutas el script<\/LI><\/OL><\/P>Notas:<\/STRONG><\/P><\/P>Actualiza la variable FeatureLayerId <\/> para ejecutar sobre tu propio Feature Layer<\/LI>Especifica tu PortalUserName, PortalPassword si el Feature Layer está protegido<\/LI>Los nombres de las carpetas están filtrados para mostrar solo caracteres 0-9 y a-Z<\/LI>Este script no ha sido probado contra ArcGIS Enterprise (solo Feature Layers alojados en ArcGIS Online), pero aún debería funcionar<\/LI>Código también disponible a través del repositorio GitHub developer-support de Esri<\/A><\/LI><\/>
Por esta razón, creé un script usando el nuevo
¿Qué hace este script?<\/STRONG><\/P><\/P>Crea una carpeta en la que se almacenan los archivos adjuntos del feature (por ejemplo, Descargas de Archivos Adjuntos)<\/LI>Dentro de esta carpeta crea una subcarpeta para cada capa en el Feature Layer especificadoSi la variable AttachmentStorage está configurada como 'GroupedFolder<\/SPAN>', los archivos adjuntos se almacenan en el formato ObjectId-AttachmentId-OriginalFileName en una sola carpeta<\/LI>Si la variable AttachmentStorage está configurada como 'IndividualFolder', se crea una nueva carpeta para cada feature con un archivo adjunto (nombrada usando el Object ID del feature), mientras que los archivos adjuntos se almacenan dentro en el formato AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Si el archivo adjunto ya existe en disco no se descargará nuevamente<\/LI>Resumen de descargas (número total de descargas y tamaño total de los archivos adjuntos) proporcionado como salida final en consola<\/LI><\/OL><\/P>¿Cómo configurarlo?<\/STRONG><\/P><\/P>Sigue la guía
Notas:<\/STRONG><\/P><\/P>Actualiza la variable FeatureLayerId <\/> para ejecutar sobre tu propio Feature Layer<\/LI>Especifica tu PortalUserName, PortalPassword si el Feature Layer está protegido<\/LI>Los nombres de las carpetas están filtrados para mostrar solo caracteres 0-9 y a-Z<\/LI>Este script no ha sido probado contra ArcGIS Enterprise (solo Feature Layers alojados en ArcGIS Online), pero aún debería funcionar<\/LI>Código también disponible a través del
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
Los miembros registrados pueden publicar, seguir actualizaciones y más. ¿Nuevo aquí? Regístrate gratis.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.