Às vezes é necessário poder administrar os anexos de alguma forma, neste artigo abordaremos certos conceitos e mais adiante no meu github terão vários exemplos que podem modificar ao seu gosto.<\/P>
Para começar, para poder acessar os serviços do ArcGIS Enterprise (Portal) ou ArcGIS Online é necessário a biblioteca arcgis, então se não a tiverem instalada devem fazê-lo (vem incluída quando se instala o ArcGIS Pro ou dentro do Python do ArcGIS Enterprise).<\/P>
Esta primeira seção permitirá que vocês acessem seu Portal ou ArcGIS Online<\/P>
#Conectar-se ao Portal
PORTAL = GIS("url", "usuario","senha")<\/P>
Dependendo do que estiverem fazendo pode ser necessário obter o token, isso é usado basicamente quando você quer ver a url dos anexos e o serviço não está público.<\/P>
token = PORTAL._con.token<\/P>
Depois disso já podemos acessar o serviço, a api do arcgis permite acessar os objetos armazenados no Portal ou ArcGIS Online, para isso desde nosso site acessaremos o endereço do serviço (é aquele que tem o ícone amarelo com vermelho). (É um texto por isso deve ir entre aspas)<\/P>
serviço = PORTAL.content.get('item id')<\/P>
Depois quando acessamos esta parte podemos ver as diferentes camadas e tabelas que possui o serviço que estamos consultando, portanto é necessário colocar o número que indica o índice da camada ou tabela, e aqui devo esclarecer, que se tivermos por exemplo: uma entidade geográfica e uma tabela ambas terão o índice 0, isso porque o sistema detecta como uma lista de camadas e uma lista de tabelas dentro do serviço, portanto, no caso de existir uma camada e uma tabela ambas têm o índice 0. Agora bem se tiverem duas camadas e uma tabela, haverá uma camada com índice 0, a outra com 1 e a tabela será 0. Espero não causar confusão com isso hehe.<\/P>
A questão é que para parametrizar fiz o seguinte:<\/P>
num_camada=int(índice)<\/P>
Nota: é um dado numérico por isso simplesmente escrevem o valor<\/P>
Como indicava anteriormente podem existir camadas ou tabelas, dessa forma, também pode ser que os anexos estejam em uma camada ou em uma tabela, por isso me vi na necessidade de adicionar algo assim à ferramenta:<\/P>
tipo="aqui se escreve camada ou tabela"
if tipo=="camada":
camada=(serviço.layers)[num_camada]
elif tipo=="tabela":
camada =(serviço.tables)[num_camada]<\/P>
Para construir a URL, a mesma API da Esri nos indica como obtê-la, só que não faz como um texto e sim como um objeto, então fiz o seguinte usando a biblioteca python re:<\/P>
cam_url=str(re.findall('htt.*'+str(num_camada), str(camada)))
cam_url=str(cam_url)[2:-2]<\/P>
Dessa forma transforma o objeto em uma string (texto)<\/P>
Agora, devemos identificar a pasta onde vamos guardar os anexos
pasta=r"endereço da pasta desejada"<\/P>
Outro parâmetro que uso é um campo de texto vazio onde armazenarei o endereço onde estão armazenados os anexos, dessa forma pode ser parametrizado com o dataframe do pandas e exatamente o que faremos aqui:<\/P>
sdf = camada.query(where="nome do campo"+" IS NULL").sdf<\/P>
Dessa forma a consulta irá somente para aqueles que têm esse campo vazio<\/P>
Depois disso gera-se uma lista vazia que capturará os registros que vamos incluir dentro de uma edição, isso será muito importante mais adiante pois permite inserir os dados dentro da lista vazia e enviá-los ao método de edição, de acordo com o que estivermos fazendo.<\/P>
elementos_a_atualizar = []<\/P>
Agora sim devemos iterar na camada ou tabela que tem os anexos<\/P>
#Iterar através do dataframe
for index, row in sdf.iterrows():
objID=str("campo que contém o objectid")
Attachments = camada.attachments.get_list(oid=objID)<\/P>
Dentro da mesma iteração coloquei um if, como podem observar nas linhas anteriores cria-se uma lista no Attachments, portanto, uma característica das listas é que podemos contar a quantidade de elementos e precisamente isso faz o if, pois consultaremos somente onde essa lista é maior que 0, assim estaremos duplamente seguros de que vamos trabalhar somente com dados que têm anexos.<\/P>
if len(Attachments)>0:<\/P>
Dentro desta condição vamos iterar os anexos correspondentes a cada ObjectId da camada principal:<\/P>
for k in range(len(Attachments)):
attachmentId = Attachments[k]['id']
attachmentName = Attachments[k]['name']
img_url = cam_url+"\/{0}\/attachments\/{1}".format(objID,attachmentId)+"?token="+token
nNomeArquivo = os.path.join(pasta, attachmentName)<\/P>
Como podem observar, obtém-se o Id do anexo e o nome, com isso concateno a url obtida anteriormente com o objectid da camada ou tabela e o Id do anexo. Assim obtém-se uma URL única para cada anexo.<\/P>
Também com isso é possível concatenar o endereço da pasta que tinha anteriormente e o nome do arquivo que tem o anexo.<\/P>
Com isso pode-se brincar um pouco, neste caso vou mostrar algo para que o sistema saiba se já foi baixado um anexo com o mesmo nome na pasta que estão indicando, portanto não baixaria esse anexo. Mas também é possível dizer para criar uma pasta para cada elemento e nessa baixar todos os anexos correspondentes a esse registro. Neste caso farei para criar o arquivo, em outra ocasião mostro como criar a pasta, que aliás está no script de download de anexos do github.<\/A><\/P>Bem como dizia, aqui a parte para verificar se o anexo existe:<\/P>
existe_arquivo=os.path.exists(nNomeArquivo)
if existe_arquivo is True:
arcpy.AddMessage("Não baixar")
else:
arcpy.AddMessage("Baixar ShapeFile "+attachmentName)<\/P>
Como podem observar uso as bibliotecas os e arcpy nesta parte, a de os é para verificar a existência ou não do arquivo na pasta indicada e arcpy neste caso é para devolver uma mensagem dentro do ArcGIS, aliás se não usarem podem substituir aqui arcpy.AddMessage por print.<\/P>
Agora já com a URL podemos baixar os anexos<\/P>
try:
arcpy.AddMessage("Obtendo a URL do ShapeFile")
request=urllib.request.urlretrieve(img_url)
req = requests.get(img_url)
file = open(nNomeArquivo, 'wb')
for chunk in req.iter_content(100000):
file.write(chunk)
file.close()
&nb... estávamos pedindo que nos devolvesse onde a lista tinha mais de 0 elementos) usaremos o método que capturará os dados e os anexará à nossa lista vazia.<\/P>
#Atualizar o campo do endereço da pasta
selecionar=capa.query(where="campo do objectid"+"="+objID)
elem_atualizar=(selecionar.features[0])
elem_atualizar.attributes["nome do campo"]=str(fileName)<\/P>
Agora anexaremos os registros que vamos capturando que têm anexos e o campo que conterá o endereço vazio
elementos_a_atualizar.append(elem_atualizar)<\/P>
Depois de ir anexando esses dados na lista vazia, com este método, procederemos a usar a lista para editar os elementos. Isso é feito fora da iteração do dataframe, ou seja, está fora de tudo.<\/P>
capa.edit_features(updates=elementos_a_atualizar)<\/P>
Como podem observar, updates indica que é igual à lista vazia que havia sido indicada anteriormente.<\/P>
E isso é tudo, tenho vários exemplos no meu
GitHub<\/A>, nestes baixo anexos e os elimino do serviço, ou simplesmente os baixo, ou em outro caso, baixo anexos que são shapefiles e os anexo a outro serviço como novas entidades, com prazer posso explicar como funcionam mais adiante.<\/P>Outra coisa muito importante que devo esclarecer é que o toolbox que se encontra anexo é para versão 3 em diante, se tiver uma versão anterior a 2.9, pois é preciso configurar o toolbox, é por isso que também anexo os scripts para que possam personalizá-lo. Deixo aqui um
link<\/A> que é um pequeno guia para configurar ferramentas com versões inferiores a 2.9<\/STRONG><\/P>Espero que ajude<\/P>
<\/P>