Рекурсивная итерация Python Playwright по каталогам SharePointPython

Программы на Python
Anonymous
 Рекурсивная итерация Python Playwright по каталогам SharePoint

Сообщение Anonymous »

Я выполняю рекурсивный доступ к каталогам, структура папок которых выглядит примерно так:
-- папка1
-- папка1.1
-- папка 1.1.1
-- папка 1.1.1.1 (здесь находятся документы, и я хочу получить даты их изменения)
-- папка2
-- папка2.1
-- папка2.1.1
-- папка2.1.1.1
-- папка3
-- папка3.1
-- папка3.1.1
-- папка3.1.1.1
Я обращаюсь к каждой папке, собираю нужную информацию, затем возвращаюсь в корень и продолжаю всю структуру, начиная с папки 1.
Итак Пока это работает, но я хотел бы знать, есть ли лучший способ справиться с нестабильностью веб-страницы, не полагаясь на эти общие ожидания. Я ищу более надежный и безопасный подход.
Вот исходный код:
class VarreduraDiretorios:
def __init__(self, services, logger, dcParameter):
self.services = services
self.logger = logger
self.dcParameter = dcParameter

def is_folder(self, linha):
icon_locator = linha.locator("[role='img']").first

label_icone = ""
if icon_locator.count() > 0:
label_icone = (icon_locator.get_attribute("aria-label") or "").lower()

is_folder = ("pasta" in label_icone) or ("folder" in label_icone)
if is_folder:
return True
else:
return False

def obter_linhas_grid(self, pagina):
"""Retorna todas as linhas do grid do SharePoint (ignora cabeçalho)."""
content = pagina.locator("#list-content-id")
pagina.wait_for_selector("#list-content-id div[role='row']")
linhas = content.locator("div[role='row']")
total = linhas.count()
return linhas, total

def _listar_pastas_no_diretorio_atual(self, pagina) -> list:
resultado = []

try:
linhas, total = self.obter_linhas_grid(pagina)
except Exception as e:
self.logger.log_warning('_listar_pastas_no_diretorio_atual', f"Falha ao obter linhas: {e}")
return resultado

for i in range(1, total):
linha = linhas.nth(i)

nome_locator = linha.locator('[data-automationid="field-LinkFilename"] span')
nome = nome_locator.inner_text().strip() if nome_locator.count() > 0 else None

if self.is_folder(linha):
resultado.append({"row_idx": i, "nome": nome})
continue

self.logger.log_info('_listar_pastas_no_diretorio_atual', f"Pastas detectadas: {len(resultado)}")

return resultado

def _coletar_datas_modificacao_no_diretorio_atual(self, pagina) -> list:
resultado = []

try:
linhas, total = self.obter_linhas_grid(pagina)
self.logger.log_info('_coletar_datas_modificacao_no_diretorio_atual', f"Total de linhas encontradas: {total}")
except Exception as e:
self.logger.log_warning('_coletar_datas_modificacao_no_diretorio_atual', f"Falha ao localizar o container da lista: {e}")
return resultado

for i in range(1, total):
try:
linha = linhas.nth(i)

nome_locator = linha.locator('[data-automationid="field-LinkFilename"] span')
nome = nome_locator.inner_text().strip() if nome_locator.count() > 0 else None

cell_modificacao = linha.locator("div[data-automationid='field-Modified']")
data_modificacao = cell_modificacao.get_attribute("title") or (cell_modificacao.inner_text().strip() if cell_modificacao.count() > 0 else None)

resultado.append({"nome": nome, "modificado": data_modificacao})
self.logger.log_info('_coletar_datas_modificacao_no_diretorio_atual', f"Arquivo: {nome} | Modificado: {data_modificacao}")
except Exception as e:
self.logger.log_warning('_coletar_datas_modificacao_no_diretorio_atual', f"Falha ao ler linha {i}: {e}")
continue

return resultado

def _entrar_pasta_por_nome(self, pagina, nome_pasta: str) -> bool:
try:
linhas, total = self.obter_linhas_grid(pagina)

for i in range(1, total):
linha = linhas.nth(i)
nome_locator = linha.locator('[data-automationid="field-LinkFilename"] span')
if nome_locator.count() == 0:
continue

nome = nome_locator.inner_text().strip()
if nome.lower() == nome_pasta.lower() and self.is_folder(linha):
self.logger.log_info("_entrar_pasta_por_nome", f"Entrando na pasta: {nome}")
nome_locator.dblclick()
pagina.wait_for_selector("#list-content-id div[role='row']", timeout=15000)
pagina.wait_for_timeout(5000)
return True

self.logger.log_error("_entrar_pasta_por_nome", f"{nome_pasta} não encontrada")
return False
except Exception as e:
print(f"_entrar_pasta_por_nome: falha ao entrar em '{nome_pasta}': {e}")
self.logger.log_error("_entrar_pasta_por_nome", f"Falha ao entrar em {nome_pasta}: {e}")
return False

def varrer_diretorio(self, pagina, link, caminho_atual: list[str] = None, nivel: int = 0, visitados=None):
if caminho_atual is None:
caminho_atual = []
if visitados is None:
visitados = set()

resultado = []

try:
pastas = self._listar_pastas_no_diretorio_atual(pagina)
if not pastas:
arquivos = self._coletar_datas_modificacao_no_diretorio_atual(pagina)
self.logger.log_info("varrer_diretorio", f"[NÍVEL {nivel}] Nenhuma subpasta, {len(arquivos)} arquivos encontrados")
return arquivos

for _, pasta in enumerate(pastas):
nome_pasta = pasta["nome"]

caminho_str = "/".join(caminho_atual + [nome_pasta])
if caminho_str in visitados:
self.logger.log_warning("varrer_diretorio", f"[NÍVEL {nivel}] Ignorando pasta já visitada: {caminho_str}")
continue
visitados.add(caminho_str)

self.logger.log_info("varrer_diretorio", f"[NÍVEL {nivel}] Entrando na pasta {nome_pasta}")

ok = self._entrar_pasta_por_nome(pagina, nome_pasta)
if not ok:
self.logger.log_error("varrer_diretorio", f"[NÍVEL {nivel}] Falha ao entrar na pasta {nome_pasta}")
continue

caminho_novo = caminho_atual + [nome_pasta]
conteudo = self.varrer_diretorio(pagina, link, caminho_novo, nivel + 1, visitados)
resultado.append({"pasta": nome_pasta, "conteudo": conteudo})

self.logger.log_info("varrer_diretorio", f"[NÍVEL {nivel}] Finalizou {nome_pasta}. Voltando ao pai...")

self.voltar_para_raiz(pagina, link)
for p in caminho_atual:
self._entrar_pasta_por_nome(pagina, p)

return resultado

except Exception as e:
self.logger.log_error("varrer_diretorio", f"ERRO em {caminho_atual}: {e}")
return resultado

def voltar_para_raiz(self, pagina, link):
try:
base_url = f"{link}"
pagina.goto(base_url)
pagina.wait_for_selector("#list-content-id div[role='row']", timeout=15000)
pagina.wait_for_timeout(5000)
except Exception as e:
self.logger.log_error("voltar_para_raiz", f"Erro: {e}")


Подробнее здесь: https://stackoverflow.com/questions/797 ... irectories

Вернуться в «Python»