Pergunta

Verifiquei novamente meu código e observei operações comparáveis ​​ao abrir uma URL para passar dados da web para o Beautiful Soup. Por algum motivo, meu código simplesmente não retorna nada, embora esteja na forma correta:

>>> from bs4 import BeautifulSoup

>>> from urllib3 import poolmanager

>>> connectBuilder = poolmanager.PoolManager()

>>> content = connectBuilder.urlopen('GET', 'http://www.crummy.com/software/BeautifulSoup/')

>>> content
<urllib3.response.HTTPResponse object at 0x00000000032EC390>

>>> soup = BeautifulSoup(content)

>>> soup.title
>>> soup.title.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'name'
>>> soup.p
>>> soup.get_text()
''

>>> content.data
a stream of data follows...

Como mostrado, está claro que urlopen() retorna uma resposta HTTP que é capturada pela variável content, faz sentido que ele possa ler o status da resposta, mas depois de passada para o Beautiful Soup, os dados da web não são convertidos em um objeto Beautiful Soup (sopa variável).Você pode ver que tentei ler algumas tags e texto, o get_text() retorna uma lista vazia, isso é estranho.

Estranhamente, quando acesso os dados da web via content.data, os dados aparecem, mas não são úteis, pois não posso usar o Beautiful Soup para analisá-los.Qual é o meu problema?Obrigado.

Foi útil?

Solução

Se você quiser apenas raspar a página, requests obterá o conteúdo que você precisa:

from bs4 import BeautifulSoup

import requests
r = requests.get('http://www.crummy.com/software/BeautifulSoup/')
soup = BeautifulSoup(r.content)

In [59]: soup.title
Out[59]: <title>Beautiful Soup: We called him Tortoise because he taught us.</title>

In [60]: soup.title.name
Out[60]: 'title'

Outras dicas

urllib3 retorna um objeto Response, que contém o .data que tem a carga útil do corpo pré-carregada.

De acordo com o início rápido principal exemplo de uso aqui, eu faria algo assim:

import urllib3
http = urllib3.PoolManager()
response = http.request('GET', 'http://www.crummy.com/software/BeautifulSoup/')

from bs4 import BeautifulSoup
soup = BeautifulSoup(response.data)  # Note the use of the .data property
...

O resto deve funcionar conforme planejado.

--

Um pouco sobre o que deu errado no seu código original:

Você passou por todo response objeto em vez da carga útil do corpo.Isso normalmente deveria estar bem porque o response object é um objeto semelhante a um arquivo, exceto neste caso, o urllib3 já consome toda a resposta e a analisa para você, para que não haja mais nada a ser feito .read().É como passar um ponteiro de arquivo que já foi lido. .data por outro lado, acessará os dados já lidos.

Se quiser usar objetos de resposta urllib3 como objetos semelhantes a arquivos, você precisará desabilitar o pré-carregamento de conteúdo, assim:

response = http.request('GET', 'http://www.crummy.com/software/BeautifulSoup/', preload_content=False)
soup = BeautifulSoup(response)  # We can pass the original `response` object now.

Agora deve funcionar como você esperava.

Entendo que este comportamento não é muito óbvio e, como autor do urllib3, peço desculpas.:) Planejamos fazer preload_content=False o padrão algum dia.Talvez algum dia em breve (Abri um issue aqui).

--

Uma nota rápida sobre .urlopen contra .request:

.urlopen assume que você cuidará da codificação de quaisquer parâmetros passados ​​para a solicitação.Neste caso, não há problema em usar .urlopen porque você não está passando nenhum parâmetro para a solicitação, mas em geral .request fará todo o trabalho extra para você, então é mais conveniente.

Se alguém quiser melhorar nossa documentação nesse sentido, ficaria muito grato.:) Por favor, envie um PR para https://github.com/shazow/urllib3 e adicione-se como colaborador!

Como mostrado, está claro que urlopen() retorna uma resposta HTTP que é capturada pela variável content…

O que você chamou content não é o conteúdo, mas um objeto semelhante a um arquivo do qual você pode ler o conteúdo.BeautifulSoup fica perfeitamente feliz em aceitar tal coisa, mas não é muito útil imprimi-la para fins de depuração.Então, vamos ler o conteúdo dele para facilitar a depuração:

>>> response = connectBuilder.urlopen('GET', 'http://www.crummy.com/software/BeautifulSoup/')
>>> response
<urllib3.response.HTTPResponse object at 0x00000000032EC390>
>>> content = response.read()
>>> content
b''

Isso deve deixar bem claro que BeautifulSoup não é o problema aqui.Mas continuando:

… mas depois de passado para o Beautiful Soup, os dados da web não são convertidos em um objeto Beautiful Soup (sopa variável).

Sim.O fato de que soup.title deu-te None em vez de levantar um AttributeError é uma evidência muito boa, mas você pode testá-la diretamente:

>>> type(soup)
bs4.BeautifulSoup

Isso é definitivamente um BeautifulSoup objeto.

Quando você passa BeautifulSoup uma string vazia, exatamente o que você receberá dependerá de qual analisador está usando nos bastidores;se estiver contando com o stdlib Python 3.x, o que você obterá é um html nó com um vazio head, e vazio body, e nada mais.Então, quando você procura um title nó, não há um, e você obtém None.


Então, como você conserta isso?

Como a documentação diz, você está usando "a chamada de nível mais baixo para fazer uma solicitação, então você precisará especificar todos os detalhes brutos". Quais são esses detalhes brutos?Honestamente, se você ainda não sabe, não deveria usar este método. Ensinando como lidar com os detalhes ocultos do urllib3 antes mesmo de você saber o básico, não estaria lhe prestando um serviço.

Na verdade, você realmente não precisa urllib3 aqui de jeito nenhum.Basta usar os módulos que acompanham o Python:

>>> # on Python 2.x, instead do: from urllib2 import urlopen 
>>> from urllib.request import urlopen
>>> r = urlopen('http://www.crummy.com/software/BeautifulSoup/')
>>> soup = BeautifulSoup(r)
>>> soup.title.text
'Beautiful Soup: We called him Tortoise because he taught us.'

Meu lindo código de sopa estava funcionando em um ambiente (minha máquina local) e retornando uma lista vazia em outro (servidor Ubuntu 14).

Resolvi meu problema alterando a instalação.detalhes em outro tópico:

A análise HTML com Beautiful Soup retorna uma lista vazia

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top