Resumo: Existem três formas sensatas de utilizar o cURL com Python: executar ocurlbinário comsubprocess, ligar-se à libcurl através do PycURL ou ignorar completamente o curl e utilizar a biblioteca Requests. Saber utilizar bem o cURL com Python significa conhecer as três opções. Este guia fornece exemplos executáveis para todas as três, uma tabela de conversão de sinalizadores do curl para Python e uma matriz de decisão para que possa escolher a ferramenta certa à primeira tentativa.
Introdução
Se escreves Python e utilizas APIs HTTP, provavelmente já te deparaste com esta situação: a documentação de uma API ou o botão «Copiar como cURL» do teu navegador fornece-te uma linha de comando que começa com curl -X POST ..., e agora precisa dela dentro de um script Python. Descobrir como usar o cURL com Python parece simples, mas tem mais do que uma resposta certa.
O cURL em si é uma ferramenta de linha de comando para transferir dados através de protocolos de rede (HTTP, HTTPS, FTP). A partir do Python, pode chamar o binário curl como um processo externo, acionar a sua biblioteca C subjacente (libcurl) através do PycURL ou usar a biblioteca Requests como uma alternativa em Python. Cada opção tem vantagens e desvantagens em termos de velocidade, controlo e facilidade de manutenção.
Este guia destina-se a engenheiros de backend, dados e scraping que já conhecem Python e procuram uma forma simples de converter qualquer fragmento de código curl em código funcional. Abordamos os três métodos com exemplos executáveis, mapeamos sinalizadores comuns do curl para os seus equivalentes em Python, construímos um pequeno pipeline de scraping e terminamos com a resolução de problemas, para que possa entregar o código em vez de lutar contra as suas ferramentas.
Por que razão os programadores executam o cURL dentro do Python
A maioria das equipas depara-se com a questão do curl no Python pela mesma razão: alguém lhes entregou um comando curl. A documentação das API fornece exemplos de pedidos como curl invocações, as ferramentas de desenvolvimento do navegador exportam chamadas de rede no mesmo formato, e o Postman e o Insomnia permitem-lhe copiar qualquer pedido como curl. Esse fragmento é a fonte da verdade, e quer que o seu código Python se comporte de forma idêntica.
Executar o curl dentro do Python permite-lhe depurar primeiro a solicitação exata e, em seguida, passar para algo mais idiomático. Uma execução de copiar-colar via subprocess comprova que o endpoint funciona. A partir daí, pode reescrever a chamada em PycURL ou Requests com a certeza de que não alterou o formato de transmissão. Esse curto ciclo de feedback é a verdadeira razão pela qual os programadores querem saber como usar o cURL com Python, e não o curl por si só.
Como usar o cURL com Python: três abordagens num relance
Quando os programadores perguntam como usar o cURL com Python, geralmente referem-se a uma de três abordagens concretas. Antes de escrever qualquer código, escolha a que melhor se adequa à tarefa. As três opções não são intercambiáveis, e escolher a errada significa, normalmente, reescrever a chamada mais tarde.
|
Abordagem |
Ideal para |
Instalação necessária |
Vantagens e desvantagens |
|---|---|---|---|
|
|
Reproduzir um trecho de código do curl na íntegra, depuração pontual, scripts de CI |
Nenhuma (curl no PATH) |
Implica um custo de criação de processo por pedido e analisa a saída em cadeias de caracteres |
|
PycURL (ligações libcurl) |
Scrapers de alto rendimento, controlo detalhado de TLS/timeout, FTP e outros protocolos |
|
API de nível inferior, problemas de compilação em alguns sistemas |
|
Biblioteca Requests |
Quase tudo o resto: APIs REST, JSON, cookies, sessões |
|
Não vem incluída com o Python; abstrai algumas opções específicas do curl |
Trate subprocess como a sua etapa de tradução, o PycURL como a sua ferramenta avançada e o Requests como o seu padrão. A maior parte do código Python de produção acaba por usar o Requests; os outros dois cobrem os casos especiais.
Método 1: subprocess: executar comandos curl diretamente
O subprocess módulo faz parte da biblioteca padrão do Python, pelo que pode recorrer ao curl sem instalar nada de novo. Esta é a interpretação mais literal de «usar o cURL com Python» e é genuinamente útil quando se pretende reproduzir um comando exatamente como aparece na documentação da API.
Uma regra de segurança inegociável: passe o comando como uma lista de argumentos, não como uma única string de shell. As strings convidam à injeção de shell quando qualquer parte da solicitação vem da entrada do utilizador. A forma de lista de argumentos ignora o shell por completo. A documentação do Python subprocess aborda o modelo de segurança em detalhe.
Insira um snippet do curl no subprocess.run
Pegue uma linha de comando curl, divida-a em tokens e passe a lista para subprocess.run. Defina capture_output=True para que stdout e stderr sejam devolvidos a si, e text=True para que obtenha cadeias de caracteres em vez de bytes.
import subprocess
cmd = [
"curl", "-s",
"-H", "Accept: application/json",
"https://httpbin.org/get?lang=python",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
print(result.stdout)A -s silença o medidor de progresso do curl para que stdout contenha apenas o corpo da resposta. O timeout=15 argumento aciona subprocess.TimeoutExpired se o curl travar, que é exatamente o que se pretende num script que não deve bloquear indefinidamente. Mantenha esta forma para tradução: assim que funcionar, terá uma base de referência verificada para portar para o PycURL ou o Requests.
Capturar a saída e verificar os códigos de retorno
Por predefinição, subprocess.run não gera uma exceção quando o curl sai com um valor diferente de zero. Tens de inspecionar o código de retorno por ti próprio ou optar explicitamente por uma exceção.
import json, subprocess
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
if result.returncode != 0:
raise RuntimeError(f"curl failed ({result.returncode}): {result.stderr.strip()}")
try:
payload = json.loads(result.stdout)
except json.JSONDecodeError as exc:
raise RuntimeError(f"non-JSON response: {result.stdout[:200]}") from exc
print(payload["args"])Também pode chamar result.check_returncode(), que gera CalledProcessError em qualquer saída diferente de zero. De qualquer forma, registe result.stderr quando a chamada falhar. O curl grava a sua saída de diagnóstico nesse local, e essa mensagem é normalmente suficiente para distinguir uma falha de DNS de um erro TLS ou de uma resposta 4xx.
Método 2: PycURL: ligações nativas à libcurl
O PycURL é uma interface Python para a libcurl, a mesma biblioteca C que alimenta o próprio binário curl. Ele expõe opções de baixo nível para tempos de espera, configuração SSL, cabeçalhos, cookies, redirecionamentos e protocolos além do HTTP. Quando a taxa de transferência ou o controlo refinado são importantes, o PycURL é a escolha certa.
Instale-o com pip install pycurl. O pacote Python é um wrapper fino, pelo que também necessita das cabeçalhos de desenvolvimento da libcurl e do OpenSSL no sistema. No Debian/Ubuntu, isso é apt install libcurl4-openssl-dev libssl-dev; no macOS, brew install curl openssl. Abordaremos os erros de ligação do OpenSSL na secção de resolução de problemas, porque são a razão mais comum pela qual uma nova instalação falha.
GET, POST e JSON com o PycURL
O PycURL segue o padrão da libcurl: criar um identificador, definir opções, executar e, por fim, fechar. As gravações vão para um buffer semelhante a um ficheiro, que geralmente é um BytesIO.
import json, pycurl
from io import BytesIO
from urllib.parse import urlencode
# GET
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/get?lang=python")
c.setopt(c.WRITEDATA, buf)
c.perform()
status = c.getinfo(pycurl.RESPONSE_CODE)
c.close()
print(status, buf.getvalue().decode("utf-8"))Para um POST codificado por formulário, defina POSTFIELDS um corpo codificado por URL. Para JSON, descarregue o dicionário e defina o Content-Type.
# POST form
form = urlencode({"a": 1, "b": "two"})
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/post")
c.setopt(c.POSTFIELDS, form)
c.setopt(c.WRITEDATA, buf)
c.perform(); c.close()
# POST JSON
body = json.dumps({"hello": "world"})
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/post")
c.setopt(c.HTTPHEADER, ["Content-Type: application/json"])
c.setopt(c.POSTFIELDS, body)
c.setopt(c.WRITEDATA, buf)
c.perform(); c.close()A configuração HTTPHEADER é como controla Content-Type, Accept, Authorization e qualquer outro cabeçalho de pedido. Vamos desenvolver esse padrão a seguir.
Cabeçalhos personalizados, cookies e redirecionamentos
HTTPHEADER aceita uma lista de "Name: value" cadeias de caracteres. Os cookies podem ser incluídos como um Cookie cabeçalho para chamadas pontuais, ou pode deixar que a libcurl gerencie um conjunto de cookies com COOKIEFILE e COOKIEJAR.
c.setopt(c.HTTPHEADER, [
"Accept: application/json",
"Authorization: Bearer eyJhbGciOi...",
"Cookie: session=abc123; theme=dark",
])
# Or use a cookie jar to persist Set-Cookie across requests
c.setopt(c.COOKIEFILE, "cookies.txt")
c.setopt(c.COOKIEJAR, "cookies.txt")Para redirecionamentos, ative FOLLOWLOCATION (o equivalente a curl -L) e limite a cadeia com MAXREDIRS para que um servidor com mau comportamento não o possa manter num loop infinito.
c.setopt(c.FOLLOWLOCATION, True)
c.setopt(c.MAXREDIRS, 5)Se precisar apenas de cabeçalhos de resposta (um curl -I pedido de estilo), defina NOBODY para True e encaminhe o fluxo de cabeçalhos para um callback através de HEADERFUNCTION. Esse callback é executado uma vez por linha de cabeçalho, o que é útil ao extrair dados como Last-Modified ou metadados de limitação de taxa. Para receitas mais detalhadas, consulte a nossa análise dos cabeçalhos de resposta HTTP no cURL.
Downloads de ficheiros em streaming com PycURL
WRITEDATA aceita qualquer objeto semelhante a um ficheiro, pelo que um download é uma alteração de uma linha: abra um ficheiro no modo de escrita binária e aponte a libcurl para ele. A utilização de memória permanece estável independentemente do tamanho da carga útil.
import os, pycurl
url = "https://example.com/large.iso"
out = "large.iso"
mode = "ab" if os.path.exists(out) else "wb"
offset = os.path.getsize(out) if mode == "ab" else 0
with open(out, mode) as fp:
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, fp)
c.setopt(c.FOLLOWLOCATION, True)
if offset:
c.setopt(c.RANGE, f"{offset}-") # resume from byte offset
c.perform(); c.close()O cabeçalho Range: bytes={offset}- cabeçalho diz ao servidor para enviar apenas a parte final que falta, que é exatamente como curl -C - retoma downloads interrompidos. O servidor deve suportar pedidos de intervalo (a maioria das CDNs suporta).
Método 3: Requests: a alternativa Pythonic ao curl
Para a maioria das tarefas diárias, o Requests é a resposta. Não vem incluído no Python (instale com pip install requests), mas a API mapeia-se perfeitamente para a semântica do curl: parâmetros de consulta, cabeçalhos, cookies, corpos JSON e tempos de espera são todos argumentos de palavra-chave.
import requests
# GET with query params
r = requests.get(
"https://httpbin.org/get",
params={"lang": "python"},
headers={"Accept": "application/json"},
timeout=15,
)
r.raise_for_status()
print(r.json())
# POST JSON
r = requests.post(
"https://httpbin.org/post",
json={"hello": "world"},
headers={"Authorization": "Bearer ..."},
timeout=15,
)raise_for_status() é o seu amigo: transforma qualquer 4xx/5xx num requests.HTTPError, pelo que a diferença entre falhas de rede (requests.ConnectionError, requests.Timeout) e erros HTTP permanece clara no seu código.
Escolha o Requests por padrão quando a chamada for uma entre muitas num programa Python, se precisar do estado da sessão ou se a sua equipa for manter o código. Escolha o PycURL quando tiver identificado um verdadeiro gargalo ou precisar de opções exclusivas da libcurl. Para uma comparação mais aprofundada dos clientes HTTP do Python, consulte o nosso resumo sobre o tema.
Traduzindo sinalizadores comuns do curl para Python
Depois de saber como usar o cURL com Python nas três variantes, a forma mais rápida de portar um novo comando é traduzir as suas flags uma a uma. Esta tabela abrange as flags que encontrará em 95% da documentação de APIs e exportações de ferramentas de desenvolvimento.
|
Sinalizador do curl |
O que faz |
PycURL |
Palavra-chave Requests |
|---|---|---|---|
|
|
Definir método HTTP |
|
|
|
|
Adicionar cabeçalho de solicitação |
|
|
|
|
Corpo codificado por URL |
|
|
|
|
Corpo bruto do ficheiro |
|
|
|
|
Corpo JSON bruto |
|
|
|
|
Formulário multiparte |
|
|
|
|
Converter dados em string de consulta |
|
|
|
|
Seguir redirecionamentos |
|
|
|
|
Autenticação básica |
|
|
|
|
Enviar cookie |
|
|
|
|
Gravar corpo no ficheiro |
|
|
|
|
Tempo limite total |
|
|
Se preferir não traduzir manualmente, existem conversores públicos de curl para Python (e o conversor do ScrapingBee é um dos mais conhecidos) que recebem um comando curl e geram uma chamada Requests com cabeçalhos, parâmetros e dados preenchidos. Use-os para iniciar o processo e, em seguida, verifique a validade da saída em relação a esta tabela.
A juntar tudo: um pipeline de scraping baseado em curl
Uma razão comum para aprender a usar o cURL com Python é o scraping da Web. Aqui está o padrão que usamos ao prototipar um pequeno scraper: buscar HTML com o PycURL para ganhar velocidade, analisá-lo com o BeautifulSoup e, em seguida, persistir o resultado. O código todo tem menos de 40 linhas e abrange verificações de estado, codificação e uma gravação em CSV.
import csv, json, pycurl
from io import BytesIO
from bs4 import BeautifulSoup
URL = "https://books.toscrape.com/catalogue/page-1.html"
def fetch(url: str) -> str:
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, buf)
c.setopt(c.FOLLOWLOCATION, True)
c.setopt(c.TIMEOUT, 20)
c.setopt(c.HTTPHEADER, ["User-Agent: scraping-pipeline/1.0"])
c.perform()
code = c.getinfo(pycurl.RESPONSE_CODE)
c.close()
if code != 200:
raise RuntimeError(f"unexpected status {code} for {url}")
return buf.getvalue().decode("utf-8")
def parse(html: str) -> list[dict]:
soup = BeautifulSoup(html, "html.parser")
rows = []
for card in soup.select("article.product_pod"):
rows.append({
"title": card.h3.a["title"],
"price": card.select_one(".price_color").text.strip(),
"stock": card.select_one(".availability").text.strip(),
})
return rows
def main():
rows = parse(fetch(URL))
with open("books.csv", "w", newline="") as fp:
writer = csv.DictWriter(fp, fieldnames=rows[0].keys())
writer.writeheader(); writer.writerows(rows)
print(json.dumps(rows[:2], indent=2))
if __name__ == "__main__":
main()Troque o PycURL pelo subprocess se quiser reproduzir um comando curl na íntegra, ou pelo Requests se precisar do estado da sessão. Assim que começar a aceder a sites reais com limites de taxa e defesas anti-bot, vai querer uma camada de proxy à frente desta etapa de obtenção.
Resolução de erros comuns do cURL com Python
A maior parte das dificuldades ao aprender a usar o cURL com Python provém de um pequeno conjunto de falhas recorrentes. Aqui está uma lista resumida e como corrigir cada uma delas.
- PycURL
ImportError: pycurl: libcurl link-time ssl backend (...) is different from compile-time ssl backend (...). O seu wheel PycURL foi compilado com um backend SSL diferente do da libcurl no seu sistema. No momento da redação deste artigo, a correção mais fiável no macOS é instalar o OpenSSL através do Homebrew e reinstalar o PycURL a partir do código-fonte com base nele; no Windows, instale os binários do OpenSSL 1.1.x e definaPYCURL_SSL_LIBRARY,LIB, eINCLUDEantespip install pycurl --no-binary :all:. Verifique novamente as notas de instalação do PycURL para a sua plataforma, pois as variáveis de ambiente exatas mudaram ao longo das versões. UnicodeEncodeErrordo PycURL em corpos POST. O PycURL espera bytes paraPOSTFIELDS. Codifique dados não ASCII explicitamente:c.setopt(c.POSTFIELDS, body.encode("utf-8")).subprocess.TimeoutExpired. Passe sempretimeout=parasubprocess.run. Trate a exceção como uma falha de rede, não como um bug.- Erros TLS e certificados autoassinados. PycURL:
c.setopt(c.SSL_VERIFYPEER, 0); Requests:verify=False. Faça isto apenas em ambientes confiáveis e dê preferência à fixação de um pacote de CA em produção. - Distinguir erros HTTP de erros de transporte. Com o Requests, capture
requests.HTTPErrorseparadamente derequests.ConnectionError. Com o subprocess, um valor diferente de zeroreturncodeé uma falha ao nível do transporte; um HTTP 4xx continua a sair com 0, a menos que passe--fail.
Escolher a abordagem certa para o seu caso de uso
Assim que tiver as três ferramentas, a escolha depende da situação.
- Depurar uma API ou reproduzir um relatório de bug. Opte por
subprocessprimeiro. Executar o comando curl literal elimina "o meu cliente Python é o problema" das variáveis. - Scripts de execução única e tarefas de CI. Requests. É legível, bem documentado e fácil de manter pelo próximo engenheiro.
- Scrapers de longa duração, volumes elevados de pedidos ou protocolos para além do HTTP. PycURL. Obtém a reutilização de ligações do libcurl, controlo TLS refinado e menor sobrecarga por pedido.
- Cookies e fluxos de login. Requests
Sessioné o caminho de menor resistência; o cookie jar do PycURL é a alternativa quando já se está a usar a libcurl.
Saber como usar o cURL com Python não se resume a escolher um vencedor, mas sim a adequar a ferramenta à solicitação.
Pontos-chave
- Três opções reais para combinar o curl com Python:
subprocess(reproduzir o binário), PycURL (ligações à libcurl) e Requests. Escolha deliberadamente, não por hábito. - Use
subprocesscomo uma camada de tradução: verifique o formato de transmissão com o comando literal e, em seguida, transfira para o PycURL ou o Requests com confiança. - Mapeie os sinalizadores do curl para Python de forma sistemática:
-Htorna-se cabeçalhos,-dtorna-se dados ou json,-Gtornam-se parâmetros,-Ftornam-se ficheiros,-Ltorna-se redirecionamentos de seguimento,-otorna-se uma gravação em fluxo. - Defina sempre tempos de espera, verifique sempre os códigos de estado e trate os erros HTTP como uma categoria distinta dos erros de transporte.
- Para scraping de grande volume ou downloads com suporte à retomada, o PycURL compensa o investimento. Para tudo o resto, opte por Requests por padrão.
Perguntas frequentes
O que significa «usar o cURL em Python»: estou a executar o binário curl ou uma biblioteca Python?
Ambos. «Executar o curl» significa normalmente chamar o curl executável do sistema a partir do Python através de subprocess, o que requer que o curl esteja no seu PATH. «Usar uma biblioteca Python» significa importar o PycURL (um wrapper em torno da libcurl) ou o Requests (um cliente HTTP em Python puro) e nunca tocar no binário. As solicitações de rede parecem idênticas para o servidor; apenas o código de chamada difere.
O PycURL é realmente mais rápido do que a biblioteca Requests em cargas de trabalho reais, ou apenas no papel?
O PycURL é geralmente mais rápido em benchmarks sintéticos porque transfere o trabalho HTTP para a libcurl em C. Em cargas de trabalho reais, a diferença diminui: a latência da rede, os handshakes TLS e a análise de dados costumam ser os fatores dominantes. O PycURL ainda leva vantagem em milhares de ligações simultâneas, onde a sobrecarga por pedido se acumula. Para a maioria dos scripts, a diferença não é mensurável.
Qual é a forma mais rápida de converter um comando curl longo da documentação da API em código Python funcional?
Cole o comando curl num conversor de curl para Python (existem vários gratuitos online), escolha a saída Requests e, em seguida, reveja o código gerado em relação à tabela de tradução de sinalizadores neste guia. O conversor lida com cabeçalhos, parâmetros e dados automaticamente. Deve ainda adicionar timeout, raise_for_status()e um tratamento de exceções adequado antes de o enviar.
Como posso enviar um upload de ficheiro multiparte (equivalente a curl -F) a partir de Python?
No Requests, use a files palavra-chave: requests.post(url, files={"upload": open("data.csv", "rb")}). Para um controlo adicional sobre o nome do ficheiro e o tipo de conteúdo, passe uma tupla: files={"upload": ("data.csv", fp, "text/csv")}. No PycURL, defina a HTTPPOST opção com uma lista de tuplas que descrevam cada campo do formulário, incluindo uma pycurl.FORM_FILE entrada para o caminho no disco.
Por que razão a minha instalação do PycURL falha com um erro de ligação do OpenSSL ou da libcurl, e como posso corrigi-lo?
Esse erro significa que o wheel foi compilado com um backend SSL que não corresponde à sua libcurl do sistema. A solução é reinstalar o PycURL a partir do código-fonte com a sua libcurl local: pip install --no-binary :all: pycurl após instalar a libcurl e os cabeçalhos de desenvolvimento do OpenSSL (brew install curl openssl no macOS; os pacotes de desenvolvimento equivalentes no Linux). No Windows, defina os caminhos do OpenSSL através de variáveis de ambiente antes de reinstalar.
Conclusão
Saber usar o cURL com Python é, na verdade, três competências numa só: chamar o binário curl com subprocess, controlar a libcurl através do PycURL e escrever código Requests idiomático. Cada um tem a sua função. subprocess é a sua etapa de tradução da documentação da API para código verificado. O PycURL é a sua ferramenta de desempenho para scrapers e downloads de alto rendimento. O Requests é o padrão para tudo o resto, porque se mantém legível à medida que o projeto cresce.
A tabela de conversão de flags para Python, a receita de download em streaming e a lista de resolução de problemas acima cobrem a maior parte das arestas. O que resta é o que o seu servidor de destino faz com o tráfego não proveniente do navegador: limites de taxa, CAPTCHAs, desafios de JavaScript e bloqueios de IP acabam por afetá-lo, por mais limpo que seja o seu código Python.
É nessa camada que nos concentramos na WebScrapingAPI. Se estás a gastar mais tempo a lutar contra defesas anti-bot do que a escrever o teu scraper, a nossa API Scraper aceita um pedido ao estilo curl e devolve o HTML bruto, tratando da rotação de proxies, resolução de CAPTCHAs e novas tentativas do seu lado, para que possas manter o teu código de subprocesso, PycURL ou Requests exatamente como está e apenas trocar o endpoint. Escolha o método curl que se adequa ao seu trabalho e deixe que a camada de rede seja problema de outra pessoa.




