J'ai souvent rencontré des questions concernant le téléchargement des pièces jointes (par exemple, photos et documents) à partir des couches d'entités ArcGIS Online. L'objectif est de fournir une solution alternative à ce qui est actuellement proposé.<\/P>
<\/P>
Premièrement, la seule façon dont les pièces jointes sont incluses lors de l'exportation des données via ArcGIS Online est lors de l'exportation en tant que File Geodatabase. La raison en est que le File Geodatabase est le seul format qui prend en charge les enregistrements liés. Par conséquent, la réponse la plus courante pour accéder aux pièces jointes des couches d'entités en dehors d'ArcGIS Online est d'exporter la couche d'entités en tant que File Geodatabase, puis d'extraire les données à l'aide d'un script comme celui-ci<\/A> via ArcGIS Desktop. Il existe également un script de synchronisation<\/A> disponible qui peut synchroniser un File Geodatabase local avec une couche d'entités hébergée. Ces solutions fonctionnent bien, mais elles dépendent d'ArcGIS Desktop, et dans le cas de la première option, nécessitent également de télécharger le File Geodatabase (qui peut augmenter en taille à mesure que vous y ajoutez des données) avant d'exécuter le script.<\/P><\/P>Pour cette raison, j'ai créé un script utilisant la nouvelle ArcGIS API for Python<\/A> qui fonctionne indépendamment d'ArcGIS Desktop. En fait, il fonctionne directement avec un Web GIS, donc vous n'avez même pas besoin de télécharger un File Geodatabase pour accéder à vos pièces jointes. Il peut être relancé régulièrement et ne télécharge sur le disque que les nouvelles pièces jointes si elles n'ont pas été téléchargées auparavant.<\/P><\/P>Que fait ce script ?<\/STRONG><\/P><\/P>Crée un dossier dans lequel les pièces jointes des entités sont stockées (par exemple Attachment Downloads)<\/LI>Dans ce dossier, crée un sous-dossier pour chaque couche dans la couche d'entités spécifiéeSi la variable AttachmentStorage est définie sur 'GroupedFolder', les pièces jointes sont stockées au format ObjectId-AttachmentId-OriginalFileName dans un seul dossier<\/LI>Si la variable AttachmentStorage est définie sur 'IndividualFolder', un nouveau dossier est créé pour chaque entité avec une pièce jointe (nommé selon l'ID de l'objet de l'entité), tandis que les pièces jointes sont stockées au format AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Si la pièce jointe existe déjà sur le disque, elle ne sera pas téléchargée à nouveau<\/LI>Résumé des téléchargements (nombre total de téléchargements et taille totale des pièces jointes) fourni en sortie finale dans la console<\/LI><\/OL><\/P>Comment s'installer ?<\/STRONG><\/P><\/P>Suivez le guide Install and set up<\/A> de l'ArcGIS API for PythonSi vous utilisez Anaconda, vous pouvez utiliser le fichier .yml pour créer l'environnement approprié<\/LI><\/OL><\/LI>Si vous utilisez le fichier Startup.bat, modifiez-le (dans un éditeur de texte) pour référencer les dossiers appropriés<\/LI>Une fois que vous avez ouvert un Jupyter Notebook, collez le fichier .zip ci-joint dans un emplacement accessible (et décompressez-le)<\/LI>Ouvrez le fichier DownloadAttachments.ipynb via Jupyter Notebooks et exécutez-le (cliquez dans le code et appuyez sur Ctrl+Enter)<\/LI>Le script s'exécutera sur la couche d'entités publique spécifiée et téléchargera les pièces jointes dans le dossier Downloads spécifié<\/LI>Un fichier journal associé est créé dans le dossier Logging chaque fois que vous exécutez le script<\/LI><\/OL><\/P>Notes :<\/STRONG><\/P><\/P>Mettez à jour la variable FeatureLayerId pour exécuter sur votre propre couche d'entités<\/LI>Spécifiez votre PortalUserName, PortalPassword si la couche d'entités est sécurisée<\/LI>Les noms des dossiers sont filtrés pour ne montrer que les caractères 0-9 et a-Z<\/LI>Ce script n'a pas été testé avec ArcGIS Enterprise (seulement les couches d'entités hébergées dans ArcGIS Online), mais il devrait quand même fonctionner<\/LI>Le code est également disponible via le dépôt GitHub Esri developer-support<\/A><\/LI><\/UL><\/BODY><\/HTML>
Pour cette raison, j'ai créé un script utilisant la nouvelle
Que fait ce script ?<\/STRONG><\/P><\/P>Crée un dossier dans lequel les pièces jointes des entités sont stockées (par exemple Attachment Downloads)<\/LI>Dans ce dossier, crée un sous-dossier pour chaque couche dans la couche d'entités spécifiéeSi la variable AttachmentStorage est définie sur 'GroupedFolder', les pièces jointes sont stockées au format ObjectId-AttachmentId-OriginalFileName dans un seul dossier<\/LI>Si la variable AttachmentStorage est définie sur 'IndividualFolder', un nouveau dossier est créé pour chaque entité avec une pièce jointe (nommé selon l'ID de l'objet de l'entité), tandis que les pièces jointes sont stockées au format AttachmentId-OriginalFileName<\/LI><\/OL><\/LI>Si la pièce jointe existe déjà sur le disque, elle ne sera pas téléchargée à nouveau<\/LI>Résumé des téléchargements (nombre total de téléchargements et taille totale des pièces jointes) fourni en sortie finale dans la console<\/LI><\/OL><\/P>Comment s'installer ?<\/STRONG><\/P><\/P>Suivez le guide
Notes :<\/STRONG><\/P><\/P>Mettez à jour la variable FeatureLayerId pour exécuter sur votre propre couche d'entités<\/LI>Spécifiez votre PortalUserName, PortalPassword si la couche d'entités est sécurisée<\/LI>Les noms des dossiers sont filtrés pour ne montrer que les caractères 0-9 et a-Z<\/LI>Ce script n'a pas été testé avec ArcGIS Enterprise (seulement les couches d'entités hébergées dans ArcGIS Online), mais il devrait quand même fonctionner<\/LI>Le code est également disponible via le
Was anyone able to name the individual attachment folders by an attribute other than objectID? I've been struggling with this for awhile.
@DanielAragon1 @JoshVan_Vlack Did you ever figure out how to include in the image name a field form the feature layer?
DanielPérez_López
I'm getting this as well, the code is executing but the files don't seem to exist in the folder? Did you resolve this?
INFO:__main__:Summary: 28 new files have been downloaded totalling 19.588373MB in size INFO:__main__:Summary: 0 attachments already existed so were not downloaded again
Hey it always works so slowly or maybe i should run the code in other environment? Im using Jupyter Notebook and in 10 minutes only 7 photos got downloaded.
Awesome, thank you for sharing your script! After adding the "[0]'s" in row 123 and 137 it worked like a charm. I havent changed anything else yet for getting an attribute value for the folder names or anything else. Already happy with this step. Thanks again!
Hi Michael.
We used your script from time to time with great success.But lately it stops with an error.
Any ideas?
Thank you 🙂
Hi Michael, I'm hoping to use this script a lot, but I've got an error that's popping up and I'm not sure how to resolve it. I'm fairly new to Python, so I'm trying to learn as I go.
As when I look into that file, below is what it's showing. Any help with what I can do to fix it?
@tk060161 Since this is using the Python API, you would have to perform some sort of attribute query. You can run this in the ArcGIS Pro python window if you would like. In the highlighted code snippet, you would just need to construct a SQL query statement that mimics the selection you were making in ArcGIS Pro.
@MattAdamssnippet above shows how to get attachments based on an attribute field query. Is it possible to do this based on a selected feature in Pro?
Hello @LuanGaspar ,
Sorry for the late response, I have added another loop to repeat the downloads for all tables as well:
for itable in range(len(itemObject.tables)): # featureTable = itemObject.tables[itable]
Then you can repeat the same thing you do for the layers
Hello @Felicitychun ,
Did you improve the script to download attachments from related table too ? If so, could you share with us?
I'm look for way to export all attachments from the survey feature and repeats tables as well on a single script.
Hello,
Great script! I am just wondering if it is at all possible to modify the name of each individual folder based on an attribute within the layer?
Thanks!
@Felicitychun Thank you for your response! It seems that your suggestion resolved that error.
Now when I run the script, it seems to feed me back the code, and the file path I tried to feed the attachments in was empty.
I really appreciate any response! A newbie to python and trying to improve!
@MichaelKelly
Hi @Anonymous User
looks like 'false' there in your code is not in brackets as a string so is trying to refer to a variable that has not been defined. In python I believe the keyword for the boolean true/false is with a capital: False
Hi anyone interested, thought I'd post my solution to my question above,
I've gotten my parent global ids using this line:
featureGuIds = featureLayer.query(where=featureFilter,out_fields=['globalid','objectid'], as_df=True,return_geometry=False)
And then I could get it when I iterate through to get the attachments as well as the object id:
currentObjectId = featureGuIds['objectid'][j] parentGlobalId = featureGuIds['globalid'][j]
Hi,
So I got the Jupyter Notebook open, I saved the attachment, and went in to customize the code to my needs. Ran the code and got this error:
NameError Traceback (most recent call last)<ipython-input-2-17b343b15353> in <module>9 "start_time": "2017-08-16T09:06:05.091046Z"10 },---> 11 "scrolled": false12 },13 "outputs": [
NameError: name 'false' is not defined
I'm trying to figure this out in the mean time, but please let me know if you can help me.
Hi @MichaelKelly ,Thanks for this, it's great!
I'm wanting to build the attachment table at the same time to get the relationships so I need the parentGlobalID. Mine doesn't have that available though:
for k in range(len(currentObjectIdAttachments)): attachmentGlobalId = currentObjectIdAttachments[k]['globalId'] attachmentParentGlobalId = currentObjectIdAttachments[k]['parentGlobalId'] attachmentId = currentObjectIdAttachments[k]['id'] attachmentName = currentObjectIdAttachments[k]['name'] attachmentSize = currentObjectIdAttachments[k]['size']
and Global ID is 'globalid' instead of 'globalID'any pointers on how do we get it from the feature as we iterate through?
Cheers
You are a lifesaver!!!!! That worked perfectly. I had been trying to figure that out for hours.... Thank you so much!
Yes! I was able to do this by using the highlighted query.
Is there a way to only download some attachments based on an attribute field? I want to be able to put in a specific project name and just download the attachments from that project (so I'm downloading 20 attachments instead of 1500). I tried this for the query (ProjectName is an attribute in my feature layer):
featureObjectIds <SPAN class="" style="color: #a67f59; background: rgba(255, 255, 255, 0.5); border: 0px; font-weight: inherit;">=</SPAN> featureLayer<SPAN class="" style="color: #999999; border: 0px; font-weight: inherit;">.</SPAN>query<SPAN class="" style="color: #999999; border: 0px; font-weight: inherit;">(</SPAN>where<SPAN class="" style="color: #a67f59; background: rgba(255, 255, 255, 0.5); border: 0px; font-weight: inherit;">=ProjectName</SPAN><SPAN class="" style="color: #669900; border: 0px; font-weight: inherit;"> == <SPAN style="color: #333333; background-color: #f7f7f7;">'9858C</SPAN>'</SPAN><SPAN class="" style="color: #999999; border: 0px; font-weight: inherit;">,</SPAN> return_ids_only<SPAN class="" style="color: #a67f59; background: rgba(255, 255, 255, 0.5); border: 0px; font-weight: inherit;">=</SPAN><SPAN class="" style="color: #990000; border: 0px; font-weight: inherit;">True</SPAN><SPAN class="" style="color: #999999; border: 0px; font-weight: inherit;">)</SPAN>
But then I got this error:
NameError: name 'ProjectName' is not defined Is there any way to do this?
Try using a service Item ID that you are familiar with. Like one that is in your own AGOL organization do not try using the default Item ID. The error you are getting is basically saying it is not finding a feature service based on the ID you are giving it.
The weird thing is I am just running the script as I downloaded it so wondering if the service that was set up for testing has now been taken down? Have you gotten the script to run recently? Maybe there are other changes that have happened that are causing the script to fail?
You may not be calling the feature correctly, the message says you have no name attribute
AttributeError: 'NoneType' object has no attribute 'name'
This script looks promising but I not sure I am set up to run it properly... Currently I am Right clicking on the original "DownloadAttachments.py" and then running "Edit with IDLE (ArcGIS Pro)" then Run > Run Module. This is what I get:
Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 14:00:49) [MSC v.1915 64 bit (AMD64)] on win32Type "help", "copyright", "credits" or "license()" for more information.>>> ================== RESTART: C:\Temp\DownloadAttachments.py ==================INFO:__main__:Script Starting at 2020-06-09 18:11:08.674435ERROR:arcgis._impl.connection:Item does not exist or is inaccessible.Traceback (most recent call last): File "C:\Temp\DownloadAttachments.py", line 77, in <module> logger.info('Iterating through layers in Feature Layer "{}"'.format(itemObject.name))AttributeError: 'NoneType' object has no attribute 'name'
I have left all of the configuration stuff alone and was trying to just see if I could get the test data to work...
Any suggestions for a novice?
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
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?
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}]}
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
Is the feature layer you're running this on publicly accessible? If yes, what's the url?
I did that step and this error popped up.
Sounds like Holly's error above, see my previous response for a solution: adding [0] to the end of the currentAttachmentPath variable
Les membres connectés peuvent publier, suivre les mises à jour, et plus encore. Nouveau ici ? Inscrivez-vous gratuitement.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.