Biblioteca de solicitações do Python (Guia) – Real Python

Assista agora Este tutorial tem um curso em vídeo relacionado, criado pela equipe do Real Python. Assista-o junto com o tutorial escrito para aprofundar sua compreensão: Como fazer solicitações HTTP com Python

O Solicitações é o padrão de fato para fazer solicitações HTTP em Python. Ela abstrai as complexidades de fazer solicitações por trás de uma API bonita e simples para que o senhor possa se concentrar na interação com os serviços e no consumo de dados em seu aplicativo.

Ao longo deste tutorial, você verá alguns dos recursos mais úteis que o Requests tem a oferecer, bem como maneiras de personalizar e otimizar esses recursos para diferentes situações que possa encontrar. O senhor também aprenderá a usar o Requests de forma eficiente e a evitar que as solicitações a serviços externos tornem o aplicativo mais lento.

Neste tutorial, o senhor aprenderá a:

  • Fazer solicitações usando os métodos HTTP mais comuns
  • Personalizar os cabeçalhos e dados de suas solicitações usando a string de consulta e o corpo da mensagem
  • Inspecionar dados de suas solicitações e respostas
  • Fazer autenticado solicitações
  • Configurar suas solicitações para ajudar a evitar que seu aplicativo sofra backups ou fique lento

Para ter a melhor experiência ao trabalhar com este tutorial, o senhor deve ter conhecimento geral básico de HTTP. Dito isso, é possível que o senhor ainda consiga acompanhar bem sem ele.

Nas próximas seções, o senhor verá como instalar e usar o requests em seu aplicativo. Se quiser brincar com os exemplos de código que verá neste tutorial, bem como com alguns outros, o senhor pode fazer download dos exemplos de código e trabalhar com eles localmente:

Primeiros passos com a biblioteca Requests do Python

Embora a biblioteca Requests seja um grampo comum para muitos desenvolvedores de Python, ela não está incluída no biblioteca padrão do Python. Existem boas razões para essa decisãoO senhor tem certeza de que a biblioteca pode continuar a evoluir mais livremente como um projeto autônomo.

Como a Requests é uma biblioteca de terceiros, o senhor precisa instalá-la antes de poder usá-la em seu código. Como boa prática, o senhor deve instalar pacotes externos em uma pasta ambiente virtualmas o senhor pode optar por instalar requests no seu ambiente global se estiver planejando usá-lo em vários projetos.

Quer esteja trabalhando em um ambiente virtual ou não, o senhor precisará instalar o requests:

Uma vez pip tiver terminado de instalar o requestso senhor pode usá-lo em seu aplicativo. Importação requests tem a seguinte aparência:

Agora que o senhor já tem tudo pronto, é hora de começar sua jornada pelos Requests. Seu primeiro objetivo será aprender a criar um GET solicitação.

A solicitação GET

Métodos HTTP, tais como GET e POSTdeterminam qual ação o senhor está tentando executar ao fazer uma solicitação HTTP. Além disso GET e POST, há vários outros métodos comuns que o senhor usará mais adiante neste tutorial.

Um dos métodos HTTP mais comuns é o GET. O GET indica que o senhor está tentando obter ou recuperar dados de um recurso especificado. Para fazer um GET usando Requests, o senhor pode invocar o requests.get().

Para testar isso, o senhor pode criar um GET para o API REST do GitHub chamando get() com o seguinte URL:

Parabéns! O senhor fez sua primeira solicitação. Agora o senhor vai se aprofundar um pouco mais na resposta dessa solicitação.

A resposta

A Response é um objeto poderoso para inspecionar os resultados da solicitação. Faça a mesma solicitação novamente, mas, dessa vez, armazene o valor de retorno em um objeto variável para que o senhor possa ver mais de perto seus atributos e comportamentos:

Neste exemplo, o senhor capturou o valor de retorno de get(), que é uma instância de Responsee a armazenou em uma variável chamada response. Agora o senhor pode usar response para ver muitas informações sobre os resultados de seu GET solicitação.

Códigos de status

A primeira informação que o senhor pode obter do Response é o código de status. O código de status informa ao senhor o status da solicitação.

Por exemplo, um 200 OK significa que sua solicitação foi bem-sucedida, enquanto um status 404 NOT FOUND significa que o recurso que o senhor estava procurando não foi encontrado. Existem muitos outros códigos de status possíveis para que o senhor tenha informações específicas sobre o que aconteceu com sua solicitação.

Ao acessar .status_code, o senhor pode ver o código de status que o servidor retornou:

.status_code retornado 200o que significa que sua solicitação foi bem-sucedida e o servidor respondeu com os dados que o senhor estava solicitando.

Às vezes, o senhor pode querer usar essas informações para tomar decisões em seu código:

Com essa lógica, se o servidor retornar um 200 status code, então seu programa irá imprimir Success!. Se o resultado for um 404, seu programa imprimirá Not Found.

O Requests dá um passo adiante na simplificação desse processo para o senhor. Se o senhor usar um Response em uma expressão condicional, ela será avaliada como True se o código de status for menor que 400, e False caso contrário.

Portanto, o senhor pode simplificar o último exemplo reescrevendo o if :

No trecho de código acima, o senhor verifica implicitamente se o .status_code do response está entre 200 e 399. Se não for, então o senhor aumentar e exceção que inclui o código de status sem êxito em um string f.

Lembre-se de que esse método é não verificando se o código de status é igual a 200. A razão para isso é que outros códigos de status dentro do 200 a 399 tais como 204 NO CONTENT e 304 NOT MODIFIEDtambém são considerados bem-sucedidos no sentido de que fornecem alguma resposta viável.

Por exemplo, o código de status 204 informa ao senhor que a resposta foi bem-sucedida, mas não há conteúdo para retornar no corpo da mensagem.

Portanto, certifique-se de usar essa abreviação conveniente somente se quiser saber se a solicitação foi bem-sucedida de modo geral. Então, se necessário, o senhor precisará tratar a resposta adequadamente com base no código de status.

Digamos que o senhor não queira verificar o código de status da resposta em um if em uma declaração. Em vez disso, o senhor deseja usar os recursos internos do Request para gerar uma exceção se a solicitação não for bem-sucedida. O senhor pode fazer isso usando .raise_for_status():

Se o senhor invocar o .raise_for_status(), o Requests gerará um erro de HTTPError para códigos de status entre 400 e 600. Se o código de status indicar uma solicitação bem-sucedida, o programa prosseguirá sem gerar essa exceção.

Agora, o senhor sabe muito sobre como lidar com o código de status da resposta que recebeu do servidor. Entretanto, quando o senhor faz uma GET raramente o senhor se preocupa apenas com o código de status da resposta. Normalmente, o senhor quer ver mais. A seguir, o senhor verá como visualizar os dados reais que o servidor enviou de volta no corpo da resposta.

Conteúdo

A resposta de um GET geralmente tem algumas informações valiosas, conhecidas como carga útil, no corpo da mensagem. Usando os atributos e métodos do Response, o senhor pode visualizar a carga útil em vários formatos diferentes.

Para ver o conteúdo da resposta em bytes, o senhor usa .content:

Enquanto .content lhe dê acesso aos bytes brutos da carga útil da resposta, muitas vezes o senhor desejará convertê-los em um string usando um codificação de caracteres tais como UTF-8. response fará isso para o senhor quando acessar .text:

Como a decodificação de bytes para um str requer um esquema de codificação, o Requests tentará adivinhar o codificação com base na resposta do cabeçalhos se o senhor não especificar uma. O senhor pode fornecer uma codificação explícita definindo .encoding antes de acessar o .text:

Se o senhor observar a resposta, verá que se trata, na verdade, de conteúdo JSON serializado. Para obter um dicionário, o senhor poderia usar o comando str que o senhor recuperou do .text e desserialize-o usando json.loads(). No entanto, uma maneira mais simples de realizar essa tarefa é usar o .json():

O type do valor de retorno do .json() é um dicionário, portanto, o senhor pode acessar os valores no objeto por chave:

O senhor pode fazer muitas coisas com códigos de status e corpos de mensagens. Mas, se o senhor precisar de mais informações, como metadados sobre a resposta em si, então o senhor precisará examinar os cabeçalhos da resposta.

Os cabeçalhos da resposta podem lhe fornecer informações úteis, como o tipo de conteúdo da carga útil da resposta e um limite de tempo para armazenar a resposta em cache. Para visualizar esses cabeçalhos, acesse .headers:

.headers retorna um objeto semelhante a um dicionário, permitindo que o senhor acesse os valores de cabeçalho por chave. Por exemplo, para ver o tipo de conteúdo da carga útil da resposta, o senhor pode acessar "Content-Type":

No entanto, há algo especial nesse objeto de cabeçalhos semelhante a um dicionário. A especificação HTTP define os cabeçalhos como insensíveis a maiúsculas e minúsculas, o que significa que o senhor pode acessar esses cabeçalhos sem se preocupar com a capitalização:

Se o senhor usar a chave "content-type" ou "Content-Type"o senhor obterá o mesmo valor.

Agora que o senhor já viu os atributos e métodos mais úteis do Response em ação, o senhor já tem uma boa visão geral do uso básico de Requests. O senhor pode obter conteúdo da Internet e trabalhar com a resposta que recebe.

Mas a Internet é mais do que URLs simples e diretos. Na próxima seção, você dará um passo atrás e verá como suas respostas mudam quando você personaliza seus GET para levar em conta os parâmetros da string de consulta.

Parâmetros da string de consulta

Uma maneira comum de personalizar um GET é passar valores por meio de string de consulta no URL. Para fazer isso, use get(), o senhor passa os dados para params. Por exemplo, o senhor pode usar o pesquisa no repositório API para procurar repositórios Python populares:

Ao passar um dicionário para a função params do parâmetro get()o senhor pode modificar os resultados que retornam da API de pesquisa.

O senhor pode passar params para get() na forma de um dicionário, como o senhor acabou de fazer, ou como uma lista de tuplas:

O senhor pode até mesmo passar os valores como bytes:

As cadeias de caracteres de consulta são úteis para parametrizar GET solicitações. Outra forma de personalizar suas solicitações é adicionar ou modificar os cabeçalhos que o senhor envia.

Para personalizar os cabeçalhos, o senhor passa um dicionário de cabeçalhos HTTP para get() usando o comando headers . Por exemplo, o senhor pode alterar sua solicitação de pesquisa anterior para destacar os termos de pesquisa correspondentes nos resultados, especificando o parâmetro text-match no parâmetro Accept cabeçalho:

O Accept informa ao servidor quais tipos de conteúdo seu aplicativo pode manipular. Nesse caso, como o senhor espera que os termos de pesquisa correspondentes sejam destacados, está usando o valor de cabeçalho application/vnd.github.text-match+json, que é um cabeçalho proprietário do GitHub Accept no qual o conteúdo é um formato JSON especial.

Se o senhor executar esse código, obterá um resultado semelhante ao mostrado abaixo:

Antes de aprender mais maneiras de personalizar as solicitações, o senhor ampliará seus horizontes explorando outros métodos HTTP.

Outros métodos HTTP

Além de GET, outros métodos HTTP populares incluem POST, PUT, DELETE, HEAD, PATCH, e OPTIONS. Para cada um desses métodos HTTP, o Requests fornece uma função, com uma assinatura semelhante à do get().

O senhor perceberá que o Requests oferece uma interface intuitiva para todos os métodos HTTP mencionados:

No código de exemplo acima, o senhor chamou cada função para fazer uma solicitação ao serviço httpbin usando o método HTTP correspondente.

O senhor pode inspecionar as respostas da mesma forma que fazia antes:

Cabeçalhos, corpos de resposta, códigos de status e muito mais são retornados na seção Response para cada método.

Em seguida, o senhor examinará mais de perto o método POST, PUT, e PATCH e saiba como eles diferem dos outros tipos de solicitação.

O corpo da mensagem

De acordo com a especificação HTTP, POST, PUTe o menos comum PATCH menos comuns, passam seus dados pelo corpo da mensagem, e não por parâmetros na string de consulta. Usando Requests, o senhor passará o payload para a função correspondente do data da função correspondente.

data O senhor pode usar um dicionário, uma lista de tuplas, bytes ou um objeto do tipo arquivo. O usuário deve adaptar os dados enviados no corpo da solicitação às necessidades específicas do serviço com o qual está interagindo.

Por exemplo, se o tipo de conteúdo da sua solicitação for application/x-www-form-urlencoded, o senhor poderá enviar os dados do formulário como um dicionário:

O senhor também pode enviar esses mesmos dados como uma lista de tuplas:

Se, no entanto, o senhor precisar enviar dados JSON, poderá usar a função json . Quando o senhor passa dados JSON via json, o Requests serializará seus dados e adicionará o parâmetro Content-Type correto para o senhor.

Como o senhor aprendeu anteriormente, o serviço httpbin aceita solicitações de teste e responde com dados sobre as solicitações. Por exemplo, o senhor pode usá-lo para inspecionar uma solicitação básica de POST básica:

A resposta mostra que o servidor recebeu os dados da solicitação e os cabeçalhos da forma como o senhor os enviou. As solicitações também fornecem essas informações ao senhor na forma de um PreparedRequest que o senhor inspecionará em mais detalhes na próxima seção.

Solicitar inspeção

Quando o senhor faz uma solicitação, a biblioteca Requests prepara a solicitação antes de enviá-la ao servidor de destino. A preparação da solicitação inclui coisas como a validação de cabeçalhos e a serialização do conteúdo JSON.

O senhor pode visualizar o PreparedRequest acessando o objeto .request em um Response objeto:

Inspeção PreparedRequest dá ao senhor acesso a todos os tipos de informações sobre a solicitação que está sendo feita, como carga útil, URL, cabeçalhos, autenticação e muito mais.

Até agora, o senhor fez vários tipos diferentes de solicitações, mas todas elas têm uma coisa em comum: são solicitações não autenticadas a APIs públicas. Muitos serviços com os quais o senhor poderá se deparar exigirão autenticação de alguma forma.

Autenticação

A autenticação ajuda um serviço a entender quem é o senhor. Normalmente, o usuário fornece suas credenciais a um servidor passando dados pelo Authorization ou um cabeçalho personalizado definido pelo serviço. Todas as funções de Requests que o senhor viu até agora fornecem um parâmetro chamado authque permite que o senhor passe suas credenciais:

A solicitação será bem-sucedida se as credenciais que o senhor passar na tupla para auth forem válidas.

Quando o senhor passa suas credenciais em uma tupla para o auth as solicitações aplicam as credenciais usando o parâmetro Esquema de autenticação de acesso básico sob o capô.

O senhor pode se perguntar onde está a string Basic dXNlcjpwYXNzd2Q= que os pedidos definiram como valor para o seu Authorization vem do cabeçalho. Em resumo, é uma cadeia de caracteres codificada em Base64 do nome de usuário e da senha com o prefixo "Basic ":

  1. Primeiro, o Requests combina o nome de usuário e a senha que o senhor forneceu, colocando dois pontos entre eles. Portanto, para o nome de usuário "user" e a senha "passwd", isso se torna "user:passwd".

  2. Em seguida, os pedidos codifica essa string em Base64 usando base64.b64encode(). A codificação converte o "user:passwd" para "dXNlcjpwYXNzd2Q=".

  3. Por fim, o Requests acrescenta "Basic " na frente dessa cadeia de caracteres Base64.

É assim que o valor final para o Authorization se torna Basic dXNlcjpwYXNzd2Q= no exemplo mostrado acima.

A autenticação HTTP Basic não é muito segura, pois é possível decodificar o nome de usuário e a senha a partir da string Base64. Por isso, é importante sempre enviar essas solicitações pelo HTTPSque fornece uma camada adicional de segurança ao criptografar toda a solicitação HTTP.

O senhor poderia fazer a mesma solicitação passando credenciais de autenticação Basic explícitas usando HTTPBasicAuth:

Embora não seja necessário ser explícito para a autenticação básica, talvez o senhor queira se autenticar usando outro método. As solicitações fornecem outros métodos de autenticação fora da caixa, como o HTTPDigestAuth e HTTPProxyAuth.

Um exemplo do mundo real de uma API que exige autenticação é a API do GitHub usuário autenticado API. Esse endpoint fornece informações sobre o perfil do usuário autenticado.

Se o senhor tentar fazer uma solicitação sem credenciais, verá que o código de status é 401 Unauthorized:

Se o senhor não fornecer credenciais de autenticação ao acessar um serviço que as exige, receberá um código de erro HTTP como resposta.

Para fazer uma solicitação à API de usuário autenticado do GitHub, primeiro o senhor precisa gerar um token de acesso pessoal com o leia:usuário escopo. Em seguida, o senhor pode passar esse token como o segundo elemento em uma tupla para get():

Como o senhor aprendeu anteriormente, essa abordagem passa as credenciais para HTTPBasicAuth, que espera um nome de usuário e uma senha e envia as credenciais como uma cadeia de caracteres codificada em Base64 com o prefixo "Basic ":

Isso funciona, mas não é a maneira correta de autenticar com um token de portador-e usar uma entrada de string vazia para o nome de usuário supérfluo é estranho.

Com o Requests, o senhor pode fornecer seu próprio mecanismo de autenticação para corrigir isso. Para experimentar isso, crie uma subclasse de AuthBase e implemente o .__call__():

Aqui, o senhor personaliza TokenAuth personalizado recebe um token e, em seguida, inclui esse token no Authorization da sua solicitação, definindo também o cabeçalho recomendado para o "Bearer " recomendado para a string.

Agora o senhor pode usar essa autenticação de token personalizado para fazer sua chamada para a API de usuário autenticado do GitHub:

Seu token personalizado TokenAuth criou uma string bem formatada para o Authorization header. Agora o senhor pode usar essa maneira mais intuitiva de interagir com um esquema de autenticação baseado em token, como o que partes da API do GitHub exigem.

Mecanismos de autenticação ruins podem levar a vulnerabilidades de segurança. A menos que um serviço exija um mecanismo de autenticação personalizado por algum motivo, o senhor sempre desejará usar um esquema de autenticação testado e comprovado, como a autenticação básica integrada ou o OAuth, por exemplo, através de Solicitações-OAuthlib.

Enquanto estiver pensando em segurança, considere lidar com certificados SSL usando Requests.

Verificação de certificados SSL

Sempre que os dados que o senhor está tentando enviar ou receber são confidenciais, a segurança é importante. A maneira pela qual o senhor se comunica com sites seguros por HTTP é estabelecendo uma conexão criptografada usando SSL, o que significa que é fundamental verificar o certificado SSL do servidor de destino.

A boa notícia é que o Requests faz isso para o senhor por padrão. No entanto, há alguns casos em que o senhor pode querer alterar esse comportamento.

Se quiser desativar a verificação do certificado SSL, passe False para o parâmetro verify da função de solicitação:

O Requests até avisa quando o usuário faz uma solicitação insegura para ajudá-lo a manter seus dados seguros!

Agora que o senhor já sabe como fazer todos os tipos de solicitações HTTP usando Requests, autenticadas ou não, talvez esteja se perguntando como pode garantir que seu programa funcione o mais rápido possível.

Na próxima seção, o senhor conhecerá algumas maneiras de melhorar o desempenho com a ajuda de Requests.

Desempenho

Ao usar Requests, especialmente em um ambiente de aplicativo de produção, é importante considerar as implicações de desempenho. Recursos como controle de tempo limite, sessões e limites de novas tentativas podem ajudá-lo a manter o aplicativo funcionando sem problemas.

Tempo limite

Quando o senhor faz uma solicitação em linha a um serviço externo, o sistema precisa aguardar a resposta antes de prosseguir. Se o seu aplicativo esperar muito tempo por essa resposta, as solicitações ao serviço poderão voltar, a experiência do usuário poderá ser prejudicada ou os trabalhos em segundo plano poderão travar.

Por padrão, as solicitações aguardam indefinidamente a resposta, portanto, quase sempre o senhor deve especificar uma duração de tempo limite para evitar que esses problemas ocorram. Para definir o tempo limite da solicitação, use o parâmetro timeout . timeout pode ser um número inteiro ou um float que representa o número de segundos a esperar por uma resposta antes de atingir o tempo limite:

Na primeira solicitação, o tempo limite da solicitação será de 1 segundo. Na segunda solicitação, o tempo limite da solicitação será de 3,05 segundos.

O senhor também pode passar uma tupla para o timeout com os dois elementos a seguir:

  1. Tempo limite de conexão: O tempo que o cliente leva para estabelecer uma conexão com o servidor
  2. Tempo limite de leitura: O tempo de espera por uma resposta quando o cliente tiver estabelecido uma conexão

Esses dois elementos devem ser números e podem ser do tipo int ou float:

Se a solicitação estabelecer uma conexão dentro de 3,05 segundos e receber dados dentro de 5 segundos após o estabelecimento da conexão, a resposta será retornada como era antes. Se a solicitação atingir o tempo limite, a função gerará um Timeout exceção:

Seu programa pode capturar o Timeout exceção e responder de acordo.

O objeto Session

Até agora, o senhor estava lidando com requests APIs de alto nível, como get() e post(). Essas funções são abstrações do que está acontecendo quando o senhor faz suas solicitações. Elas ocultam detalhes de implementação, como a forma como as conexões são gerenciadas, para que o senhor não precise se preocupar com eles.

Por baixo dessas abstrações há uma classe chamada Session. Se precisar ajustar o controle sobre como as solicitações estão sendo feitas ou melhorar o desempenho das solicitações, talvez seja necessário usar uma classe Session diretamente.

As sessões são usadas para manter os parâmetros entre as solicitações. Por exemplo, se o senhor quiser usar a mesma autenticação em várias solicitações, poderá usar uma sessão:

Neste exemplo de código, o senhor usa um gerenciador de contexto para garantir que a sessão libere os recursos quando não precisar mais deles.

Na linha 7, o usuário faz o login usando seu TokenAuth. O senhor só precisa fazer login uma vez por sessão e, depois, pode fazer várias solicitações autenticadas. As solicitações manterão as credenciais enquanto a sessão existir.

Em seguida, o senhor faz duas solicitações à API de usuário autenticado nas linhas 9 e 10 usando session.get() em vez de get().

A principal otimização de desempenho das sessões vem na forma de conexões persistentes. Quando seu aplicativo faz uma conexão com um servidor usando uma sessão Sessionele mantém essa conexão em um pool de conexões. Quando o aplicativo quiser se conectar ao mesmo servidor novamente, ele reutilizará uma conexão do pool em vez de estabelecer uma nova.

Máximo de tentativas

Quando uma solicitação falha, o senhor pode querer que seu aplicativo tente novamente a mesma solicitação. No entanto, por padrão, o Requests não fará isso para o senhor. Para aplicar essa funcionalidade, o senhor precisa implementar um adaptador de transporte personalizado.

Os adaptadores de transporte permitem que o senhor defina um conjunto de configurações para cada serviço com o qual está interagindo. Por exemplo, digamos que o senhor queira que todas as solicitações para o https://api.github.com tentem novamente duas vezes antes de finalmente gerar um RetryError. O senhor criaria um adaptador de transporte, definiria seu max_retries e montá-lo em um adaptador de transporte existente do Session:

Neste exemplo, o senhor configurou sua sessão para que ela tente novamente no máximo duas vezes quando sua solicitação à API do GitHub não funcionar como esperado.

Quando o senhor monta o HTTPAdapter-neste caso, github_adapter-para session, então session irá aderir à sua configuração para cada solicitação ao https://api.github.com.

Se o senhor quiser brincar com o código que se baseia nesse exemplo e quiser inspecionar quando as novas tentativas acontecem, está com sorte. O senhor pode fazer o download dos materiais deste tutorial e dar uma olhada em retry_thrice.py:

O código neste arquivo aprimora o exemplo mostrado acima, usando o urllib3.util.Retry subjacente para personalizar ainda mais a funcionalidade de repetição. Ele também adiciona registro em log para exibir a saída de depuração, o que lhe dá a chance de monitorar quando o Python tentou as novas tentativas.

O Requests vem com implementações intuitivas para tempos limite, adaptadores de transporte e sessões que podem ajudá-lo a manter seu código eficiente e seu aplicativo resiliente.

Conclusão

Bom trabalho, o senhor chegou ao final do tutorial e já percorreu um longo caminho para aumentar seu conhecimento sobre a poderosa biblioteca Requests do Python.

Neste tutorial, o senhor aprendeu a:

  • Fazer solicitações usando uma variedade de métodos HTTP diferentes, como GET, POST, e PUT
  • Personalize suas solicitações modificando cabeçalhos, autenticação, strings de consulta e corpos de mensagens
  • Inspecionar os dados que o senhor envia para o servidor e os dados que o servidor envia de volta para o senhor
  • Trabalhe com Verificação do certificado SSL
  • Use as solicitações de forma eficaz com max_retries, timeout, sessões e adaptadores de transporte

Como aprendeu a usar as Requests, o senhor está preparado para explorar o vasto mundo dos serviços da Web e criar aplicativos incríveis usando os dados fascinantes que eles fornecem.

Assista agora Este tutorial tem um curso em vídeo relacionado, criado pela equipe do Real Python. Assista-o junto com o tutorial escrito para aprofundar sua compreensão: Como fazer solicitações HTTP com Python