Source code for dgi.acesso.facilidade

from loguru import logger

import os
import pathlib
from time import sleep
from datetime import datetime

import requests
import urllib
import urllib.request
from http import cookiejar
from bs4 import BeautifulSoup

import pandas as pd

from pymongo import MongoClient

from multiprocessing import Process

from dgi.utils import define_ambiente_de_processamento
from dgi.info import DB_PROPS
from dgi.urls import URL_CARINHO, URL_CONFIRMA_PEDIDO, URL_FECHA_PEDIDO, URL_LOGIN
from dgi.acesso.utils import divide_lista, cria_documento_download, string_para_data

from dgi.decoradores import adiciona_log
from dgi.banco import GeradorDeConexoesMongo
from dgi.acesso.utils import remove_imagens_duplicadas
from dgi.excecoes import ErroAoAcessarLink, LimiteDoPedidoExcedido


[docs]class FacilitaDGI: """Classe que facilita a interação com o catálogo DGI/INPE Args: usuario (str): Nome de usuário no catálogo da DGI/INPE senha (str): Senha de usuário no catálogo da DGI/INPE db_props (dict): Dicionário contendo as informações para conexão com o banco de dados, contendo as seguintes chaves host: ``str``: Endereço de IP do banco de dados porta: ``int``: Porta do banco de dados usuario: ``str``: Usuário para utilizar o banco (Opcional) senha: ``str``: Senha para utilizar o banco (Opcional) """ def __init__(self, usuario, senha, db_props=DB_PROPS): self.__usuario = usuario self.__senha = senha self.__db_props = db_props self.__ambiente_de_execucao = define_ambiente_de_processamento() @adiciona_log("/tmp/pedidos_{}.log") def realiza_pedido(self, lista_de_imagens) -> dict: """Função para fazer pedidos automatizados no catálogo DGI/INPE Esta função recebe a lista de dicionários com os parâmetros das imagens (Presentes no catalogo do LabISA) e remove os elementos duplicados, então realiza o pedido Args: lista_de_image (list): Lista com as imagens que devem estar nos pedidos Returns: dict: Dicionário contendo as informações do pedido realizado. Neste dicionário há a quantidade de imagens no pedido e as imagens propriamente dito. """ informacoes_do_pedido = { "quantidade_de_imagens_no_pedido": 0, "imagens_no_pedido": set() } informacoes_do_pedido["imagens_no_pedido"] = remove_imagens_duplicadas(lista_de_imagens) informacoes_do_pedido["quantidade_de_imagens_no_pedido"] = len(informacoes_do_pedido["imagens_no_pedido"]) if informacoes_do_pedido["quantidade_de_imagens_no_pedido"] > 200: raise LimiteDoPedidoExcedido("Seu pedido deve ter no máximo 200 itens") logger.info("Iniciando processo de aquisição de imagens") cj = cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) logger.info("Fazendo login"); sleep(1) login_data = urllib.parse.urlencode({ 'name' : self.__usuario, 'pwd' : self.__senha, 'enviar': 'Realizar acesso', 'submitted': 1 }) # Ao criar uma conexão com opener, os cookies da página serão salvos opener.open(URL_LOGIN, login_data.encode()) logger.info("Recuperando sessão..."); sleep(1) cookies = opener.handlers[-2] # Recuperando apenas o PHPSESSID sess_id = str(cookies.cookiejar).split("PHPSESSID")[1].split()[0].split("=")[1] logger.info("Adicionando imagem(s) ao carrinho"); sleep(1) for imagem in informacoes_do_pedido["imagens_no_pedido"]: try: opener.open(URL_CARINHO.format(imagem)) logger.info("{}: Adicionada com sucesso!".format(imagem)) except: logger.error("Erro ao adicionar: {}".format(imagem)) logger.info("Confirmando pedido"); sleep(1) # Envia pedido de confirmação do pedido opener.open(URL_CONFIRMA_PEDIDO.format(self.__usuario, sess_id)) logger.info("Fechando pedido"); sleep(2) # Após o pedido confirmado, fecha ele para receber as imagens try: opener.open(URL_FECHA_PEDIDO.format(sess_id, self.__usuario, str(len(lista_de_imagens)))) except Exception as e: logger.error(str(e)) raise ErroAoAcessarLink("Erro ao tentar fechar o pedido") logger.success("Pedido finalizado! Verifique seu email") return informacoes_do_pedido @adiciona_log("/tmp/downloads_{}.log") def baixa_imagens_de_link_do_pedido(self, link_de_pedido, diretorio_de_saida, nprocessos=5) -> pd.DataFrame: """Função para realizar o download através de um link de pedido Args: link_de_pedido (str): Link do local onde as imagens do pedido foram disponibilizadas diretorio_de_saida (str): Diretório onde os dados deverão ser salvos nprocessos (int): Número de processos de requisição executados ao mesmo tempo Returns: pd.DataFrame: DataFrame contendo a relação de todas as imagens já baixadas neste computador """ def baixa_lista_de_links(links: list, diretorio_de_saida: str) -> None: """Função para download dos dados Args: links (list): Lista com os links que serão baixados diretorio_de_saida (str): Caminho completo para o diretório onde a imagem será salva Returns: None """ colecao = GeradorDeConexoesMongo.recupera_conexao(self.__db_props).dgi_dumps.imagens_adquiridas for link in links: divide_em = -1 complemento = "" if "scenario" in link: divide_em = -2 complemento = "scenario" doc_db = cria_documento_download(link.split("/")[divide_em]) # Caso haja arquivos do scenario, o complemento irá criar o diretório a ser utilizado diretorio_da_imagem = os.path.join(diretorio_de_saida, "{}/{}/{}/{}_{}".format(*doc_db.values()), complemento) # Criando o diretório da imagem pathlib.Path(diretorio_da_imagem).mkdir(parents=True, exist_ok=True) path = os.path.join(diretorio_da_imagem, link.split("/")[-1]) logger.info("Processando arquivo: {}".format(link)) urllib.request.urlretrieve(link, path) if "scenario" not in diretorio_da_imagem and len(list(colecao.find({"local": diretorio_da_imagem}))) == 0: doc_db["local"] = diretorio_da_imagem doc_db["data_insercao_no_banco"] = datetime.now() doc_db["data"] = string_para_data(doc_db["data"], reverso=False, sep="_") colecao.insert_one(doc_db) if link_de_pedido[-1] != '/': link_de_pedido += '/' res = requests.get(link_de_pedido) soup = BeautifulSoup(res.content, features="lxml") links_validos = [] logger.info("Verificando os links que podem ser baixados") # Criando lista de links validos for link in soup.find_all("a")[1:]: if "scenario" in link["href"]: # Caso em que o link representa um diretório r = requests.get(link_de_pedido + str(link["href"])) s = BeautifulSoup(r.content, features="lxml").findAll("a") for i in s[1:]: links_validos.append(link_de_pedido + str(link["href"]) + i["href"]) else: links_validos.append(link_de_pedido + str(link["href"])) links_divididos = divide_lista(links_validos, nprocessos) logger.info("Iniciando os downloads") for i in range(0, nprocessos): p = self.__ambiente_de_execucao(target=baixa_lista_de_links, args=(links_divididos[i], diretorio_de_saida,)) p.start() p.join() logger.success("As imagens foram salvas com sucesso!") # Recuperando as imagens já baixadas, salvas no banco colecao = GeradorDeConexoesMongo.recupera_conexao(self.__db_props).dgi_dumps.imagens_adquiridas return pd.DataFrame(list(colecao.find({}, {"_id": 0})))