2012-04-25 23 views
8

Estoy tratando de raspar los datos de la tabla en un archivo CSV. Lamentablemente, he golpeado un bloque de carretera y el siguiente código simplemente repite el TD del primer TR para todos los TR siguientes.Python beautifulsoup iterar sobre la tabla

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) 

Este es mi primer script de Python por lo que cualquier ayuda sería apreciada. He revisado otras respuestas a preguntas, pero no puedo entender qué estoy haciendo mal aquí.

Respuesta

26

Estás empezando en el nivel superior del documento cada vez que utilice find() o find_all(), por lo que cuando se pide, por ejemplo, todos los "td" `etiquetas que está recibiendo todos los tags "TD" en el documento,, no solo aquellos en la tabla y fila que ha buscado. Es mejor que no los busque porque no están siendo utilizados de la forma en que se escribe su código.

creo que quiere hacer algo como esto:

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

O, ya sabes, algo de la misma familia, con los nombres de variables más descriptivos de arranque:

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

El problema es que cada vez que intentas reducir tu búsqueda (obtener la primera td en este truco, etc.) estás simplemente volviendo a llamar a la sopa. Soup es el objeto de nivel superior: representa todo el documento. Solo necesita llamar a la sopa una vez, y luego usar el resultado de eso en lugar de sopa para el siguiente paso.

Por ejemplo (con los nombres de variables cambiaron a ser más clara),

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) 

no estoy seguro de que la declaración de impresión es la mejor manera de hacer lo que estamos tratando de hacer aquí (en el mismo al menos, debería usar el formato de cadenas en lugar de la suma), pero lo dejo tal como está, porque no es el problema central.

Además, para completar: soup.unicode no hará nada. No estás llamando a un método allí, y no hay ninguna tarea. No recuerdo que BeautifulSoup tenga un método llamado Unicode en primer lugar, pero estoy acostumbrado a BS 3.0, por lo que puede ser nuevo en 4.