E foi assim que tudo começou. Com um singelo e modesto "deu merda". Primeiramente uma rápida introdução pra explicar o que isso significa: temos um bot pra adicionar assuntos nas pautas do canal Unix Load On. O bot roda em Python no raspberrypi3 que tenho aqui em casa. O mesmo que fica tirando fotos pela janela e mostra no twitter no perfil @helio_weather.
Então temos essa função "/addpauta" com um estilo de inglês a la Raimundos pra adicionar novos links. O programa no bot rodava um código com módulo requests pra pegar a página e buscar o título do artigo. Só isso. Então não era algo esperado pra ter o resultado "deu merda". Mas deu.
Olhando a mesma URL usando o ipython:
> ipython3
Python 3.9.7 (default, Sep 10 2021, 14:59:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.20.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import requests
In [2]: url = "https://www.theregister.com/2021/11/02/fedora_35/"
In [3]: r = requests.get(url)
In [4]: r.status_code
Out[4]: 103
In [5]: r.text
Out[5]: ''
então é isso. O webserver retorna 103, que é uma nova RFC, e espera que você continue pegando o conteúdo. Só que o módulo requests não faz isso.
Existe um bug aberto no github sobre esse problema onde eles relatam que o comportamento não é bem do requests, mas da urllib3, que é parte do core do Python. Traduzindo em miúdos: não tem solução e talvez façam uma correção no Python 3.10.
Atualizar todo o Python só pra corrigir um erro besta desses? Entra em cena o curl, que já comentei em usando curl pra monitorar um site. Não o curl propriamente dito, mas a pycurl. Tanto curl quanto pycurl passam dando tchauzinho por esse problema de manipular a resposta 103. E mandam aquele abraço pra urllib3.
Olhando via script:
> curl -s https://www.theregister.com/2021/11/02/fedora_35/ | head -10
<!doctype html>
<html lang="en">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Fedora 35 released with GNOME 41 desktop • The Register</title>
<meta name="robots" content="max-snippet:-1, max-image-preview:standard, max-video-preview:0">
<meta name="viewport" content="initial-scale=1.0, width=device-width"/>
<meta property="og:image" content="https://regmedia.co.uk/2021/11/02/fedora35.jpg"/>
<meta property="og:type" content="article" />
<meta property="og:url" content="https://www.theregister.com/2021/11/02/fedora_35/" />
fazendo o mesmo em Python:
import pycurl
from io import BytesIO
def curl(url):
crl = pycurl.Curl()
crl.setopt(crl.URL, url)
b_obj = BytesIO()
crl.setopt(crl.WRITEDATA, b_obj)
crl.setopt(crl.FOLLOWLOCATION, True)
crl.setopt(pycurl.USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0')
crl.perform()
crl.close()
return b_obj.getvalue().decode('utf-8')
print(curl("https://www.theregister.com/2021/11/02/fedora_35/"))
então fica aqui a lição: onde a requests falhar, pycurl estará lá pra te salvar.