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
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
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.