Passare i dati web in Beautiful Soup-Lista vuota
-
26-12-2019 - |
Domanda
Ho ricontrollato il mio codice e ho esaminato operazioni comparabili sull'apertura di un URL per passare i dati web in Beautiful Soup, per qualche motivo il mio codice non restituisce nulla sebbene sia in forma corretta:
>>> 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...
Come mostrato, è chiaro che urlopen () restituisce una risposta HTTP che viene catturata dal contenuto della variabile, ha senso che possa leggere lo stato della risposta, ma dopo che è passato in Beautiful Soup, i dati Web non vengono convertiti in un oggetto Beautiful Soup (variable soup).Puoi vedere che ho provato a leggere alcuni tag e testo, get_text() restituisce una lista vuota, questo è strano.
Stranamente, quando accedo ai dati web tramite il contenuto.data, i dati si presentano ma non è utile dal momento che non posso usare Beautiful Soup per analizzarlo.Qual è il mio problema?Grazie.
Soluzione
Se vuoi solo raschiare la pagina, requests
otterrà il contenuto di cui hai bisogno:
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'
. Altri suggerimenti
urllib3 restituisce un oggetto di risposta, che contiene .data
che ha il carico utile del corpo precaricato.
Per la parte superiore quickstart esempio di utilizzo qui, Farei qualcosa come questo:
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
...
Il resto dovrebbe funzionare come previsto.
--
Un po ' su cosa è andato storto nel tuo codice originale:
Hai superato l'intero response
oggetto piuttosto che il carico utile del corpo.Questo dovrebbe normalmente andare bene perché il response
object è un oggetto simile a un file, tranne in questo caso urllib3 consuma già tutta la risposta e la analizza per te, in modo che non rimanga nulla .read()
.È come passare un filepointer che è già stato letto. .data
d'altra parte accederà ai dati già letti.
Se si desidera utilizzare gli oggetti di risposta urllib3 come oggetti simili a file, è necessario disabilitare il precaricamento del contenuto, in questo modo:
response = http.request('GET', 'http://www.crummy.com/software/BeautifulSoup/', preload_content=False)
soup = BeautifulSoup(response) # We can pass the original `response` object now.
Ora dovrebbe funzionare come ti aspettavi.
Capisco che questo non è un comportamento molto ovvio, e come autore di urllib3 mi scuso.:) Abbiamo intenzione di fare preload_content=False
il default un giorno.Forse un giorno presto (Ho aperto un problema qui).
--
Una breve nota su .urlopen
vs .request
:
.urlopen
presuppone che si prenderà cura di codificare tutti i parametri passati alla richiesta.In questo caso va bene usare .urlopen
perché non stai passando alcun parametro alla richiesta, ma in generale .request
farà tutto il lavoro extra per te, quindi è più conveniente.
Se qualcuno volesse migliorare la nostra documentazione in tal senso, sarebbe molto apprezzato.:) Si prega di inviare un PR a https://github.com/shazow/urllib3 e aggiungetevi come contributore!
.Come mostrato, è chiaro che urlopen () restituisce una risposta http che viene catturata dal contenuto della variabile ...
Quello che hai chiamato content
non è il contenuto, ma un oggetto simile a file che puoi leggere il contenuto da. BeautifulSoup è perfettamente felice prendendo una cosa del genere, ma non è molto utile stamparlo per scopi di debug. Quindi, effettivamente leggiamo il contenuto per rendere questo più facile da eseguire il debug:
>>> response = connectBuilder.urlopen('GET', 'http://www.crummy.com/software/BeautifulSoup/')
>>> response
<urllib3.response.HTTPResponse object at 0x00000000032EC390>
>>> content = response.read()
>>> content
b''
.
Questo dovrebbe renderlo abbastanza chiaro che BeautifulSoup
non è il problema qui. Ma continuando su:
.... Ma dopo che è passato nella bellissima zuppa, i dati del web non vengono convertiti in un bellissimo oggetto zuppa (zuppa variabile).
Sì lo fa. Il fatto che soup.title
ti ha dato None
invece di sollevare un AttributeError
è una buona prova, ma puoi testarlo direttamente:
>>> type(soup)
bs4.BeautifulSoup
.
è sicuramente un oggetto BeautifulSoup
.
Quando si passa BeautifulSoup
una stringa vuota, esattamente ciò che recuperà dipenderà da quale parser sta usando sotto le coperte; Se si basa sul Python 3.x StDlib, ciò che otterrai è un nodo html
con un head
vuoto e vuoto body
e nient'altro. Quindi, quando cerchi un nodo title
, non ce n'è uno e ottieni None
.
.
Allora, come risolvi questo?
>>> # 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.'
. Il mio bellissimo codice di zuppa funzionava in un ambiente (la mia macchina locale) e restituire una lista vuota in un altro (server Ubuntu 14).
Ho risolto il mio problema cambiando l'installazione. Dettagli in Altro filo:
HTML Parsing con bellissima zuppa restituisce la lista vuota .