2012-04-25 1 views
8

Sto provando a raschiare i dati della tabella in un file CSV. Sfortunatamente, ho colpito un blocco stradale e il codice seguente ripete semplicemente il TD dal primo TR per tutti i TR successivi.Python beautifulsoup iterate over table

import urllib.request 
from bs4 import BeautifulSoup 

f = open('out.txt','w') 

url = "http://www.international.gc.ca/about-a_propos/atip-aiprp/reports-rapports/2012/02-atip_aiprp.aspx" 
page = urllib.request.urlopen(url) 

soup = BeautifulSoup(page) 

soup.unicode 

table1 = soup.find("table", border=1) 
table2 = soup.find('tbody') 
table3 = soup.find_all('tr') 

for td in table3: 
    rn = soup.find_all("td")[0].get_text() 
    sr = soup.find_all("td")[1].get_text() 
    d = soup.find_all("td")[2].get_text() 
    n = soup.find_all("td")[3].get_text() 

    print(rn + "," + sr + "," + d + ",", file=f) 

Questo è il mio primo script Python in assoluto, quindi qualsiasi aiuto sarebbe apprezzato! Ho dato un'occhiata alle altre domande, ma non riesco a capire cosa sto facendo male qui.

risposta

26

Stai iniziando al livello superiore del documento ogni volta che si utilizza find() o find_all(), in modo che quando si chiede, ad esempio, tutti i "td" `tag che stai ricevendo tutte le "TD" tag nel documento,, non solo quelli nella tabella e nella riga che hai cercato. Si potrebbe anche non cercare quelli perché non vengono utilizzati come il tuo codice è scritto.

penso che si vuole fare qualcosa di simile:

table1 = soup.find("table", border=1) 
table2 = table1.find('tbody') 
table3 = table2.find_all('tr') 

Oppure, si sa, qualcosa di più simile a questo, con i nomi delle variabili più descrittivi per l'avvio:

rows = soup.find("table", border=1).find("tbody").find_all("tr") 

for row in rows: 
    cells = row.find_all("td") 
    rn = cells[0].get_text() 
    # and so on 
6

Il problema è che ogni volta che stai cercando di restringere la tua ricerca (prendi il primo td in questo tr, ecc.) invece stai semplicemente richiamando la zuppa. Zuppa è l'oggetto di livello superiore - rappresenta l'intero documento. Devi solo chiamare zuppa una volta, e poi usare il risultato di quello in sostituzione della zuppa per il prossimo passo.

Per esempio (con i nomi delle variabili modificate per essere più chiari),

table = soup.find('table', border=1) 
rows = table.find_all('tr') 

for row in rows: 
    data = row.find_all("td") 
    rn = data[0].get_text() 
    sr = data[1].get_text() 
    d = data[2].get_text() 
    n = data[3].get_text() 

    print(rn + "," + sr + "," + d + ",", file=f) 

non sono sicuro che la dichiarazione di stampa è il modo migliore per fare ciò che si sta cercando di fare qui (per lo per lo meno, dovresti usare la formattazione delle stringhe anziché l'aggiunta), ma lo sto lasciando così com'è perché non è il problema principale.

Inoltre, per il completamento: soup.unicode non farà nulla. Non stai chiamando un metodo lì, e non c'è nessun incarico. Non ricordo che BeautifulSoup abbia un metodo chiamato unicode in primo luogo, ma sono abituato a BS 3.0 quindi potrebbe essere nuovo in 4.