/ #requests #web 

Baixando arquivos da internet

No artigo expresso de hoje, vamos aprender a baixar um arquivo em Python com o módulo requests. Vou te apresentar logo uma versão preliminar da parte principal do código; em seguida, vamos compreender cada linha e, finalmente, implementaremos uma melhoria.

É necessário instalar o módulo requests antes. Com o pip, temos:

pip install requests

Versão preliminar do código:

import requests 

def baixar_arquivo(url, endereco):
    resposta = requests.get(url)
    if resposta.status_code == requests.codes.OK:
        with open(endereco, 'wb') as novo_arquivo:
                novo_arquivo.write(resposta.content)
        print("Download finalizado. Arquivo salvo em: {}".format(endereco))
    else:
        resposta.raise_for_status()

Você pode notar uma função com dois argumentos: url e endereço. URL é a sigla de (Uniform Resource Locator - Localizador Uniforme de Recurso), representa o “link” na internet daquilo que você quer baixar. Já endereco é uma variável que representa o endereço local para onde o arquivo deve ser salvo no computador.

Requisições HTTP com requests

A mágica toda acontece na primeira linha da função. Com o módulo requests, fazemos uma requisição do tipo GET com o protocolo HTTP (ou HTTPS), a mesma coisa que o seu navegador de internet faz para solicitar páginas e outros arquivos a um servidor. Assim, depois desta linha, a variável resposta será o nosso ponto de acesso aos dados que foram respondidos pelo servidor, tais como cabeçalhos (headers), código de status (status code) e o próprio conteúdo da requisição (nosso arquivo!).

Muita coisa pode dar errado nesse processo, podemos estar sem acesso à internet, podemos digitar uma URL inválida, o link pode estar “quebrado”, pode ser necessário estar autenticado para ter acesso ao arquivo, enfim… Por conta disso, verificamos se o código de status da requisição representa o status OK (200), significando que tudo deu certo. Se houver algum problema, caímos no fluxo do else e lançamos uma exceção, que se não for tratada, vai encerrar o programa com um erro.

Com o status OK, podemos acessar o conteúdo com segurança. Criamos uma referência para um arquivo no endereço passado à função e pedimos para escrever o conteúdo da resposta neste arquivo. Não importa qual seja o tipo de arquivo, no fim das contas ele é sempre uma sequência de bytes, por isso, ao invés de pedir para abrir o arquivo para escrita apenas com “w” (usado para arquivos de text), utilizamos “wb”, que é o modo de escrita binário, para bytes. Repare no uso da cláusula with para que a referência ao arquivo exista apenas em seu escopo, sendo fechado automaticamente logo após.

Melhorias

Se o arquivo for muito grande, podemos ter problemas em mantê-lo completamente na memória principal do computador. Nesse caso, gostaríamos de recebê-lo por partes e ir salvando cada parte no disco à medida que recebemos. É isso que o seu browser faz. Podemos obter esse resultado efetuando as seguintes mudanças:

def baixar_arquivo(url, endereco):
    resposta = requests.get(url, stream=True) #AQUI
    if resposta.status_code == requests.codes.OK:
        with open(endereco, 'wb') as novo_arquivo:
                for parte in resposta.iter_content(chunk_size=256): #AQUI TBM
                    novo_arquivo.write(parte)
        print("Download finalizado. Arquivo salvo em: {}".format(endereco))
    else:
        resposta.raise_for_status()

Na requisição GET, adicionamos o parâmetro stream=True para ler o conteúdo na forma de stream, fluxo. Em seguida, ao invés de ler diretamente o atributo content, da resposta, iteramos sobre iter_content passando 256 bytes como tamanho das partes (fragmentos). Assim, escrevemos no arquivo os bytes recebidos em cada iteração.

Outra melhoria que podemos fazer é tentar preencher o endereço do arquivo automaticamente. Podemos manter a opção de recebermos o endereço como parâmetro, mas caso nada seja passado, a gente tenta inferir:

import os

def baixar_arquivo(url, endereco=None):
    if endereco is None:
        endereco = os.path.basename(url.split("?")[0])
    (...)

Descartamos os possíveis parâmetros na URL (quando existem, vêm depois do “?”) e pegamos o último segmento da URL, após a última barra, como nome do arquivo. Assim, construímos um endereço local relativo ao diretório onde o programa estiver sendo executado.

Isso é tudo o que precisamos por hoje! Você pode encontrar a versão final do código neste link. Se você estiver lendo este artigo enquanto eu ainda não tenho uma área de comentários no site, pode deixar suas dúvidas, comentários e sugestões no canal Python Café ou nas redes sociais.

Author

Hallison Paz

Sonhador | Engenheiro de computação - pretende explorar outros corpos celestes