Estoy aprendiendo Python requestsy BeautifulSoup. Como ejercicio, he optado por escribir un analizador rápido de multas de estacionamiento de la ciudad de Nueva York. Puedo obtener una respuesta html que es bastante fea. Necesito agarrar lineItemsTabley analizar todas las entradas.
Puedes reproducir la página yendo aquí: https://paydirect.link2gov.com/NYCParking-Plate/ItemSearche ingresando una NYplacaT630134C
soup = BeautifulSoup(plateRequest.text)
#print(soup.prettify())
#print soup.find_all('tr')
table = soup.find("table", { "class" : "lineItemsTable" })
for row in table.findAll("tr"):
cells = row.findAll("td")
print cells
¿Puede alguien ayudarme? La simple búsqueda de todos trno me lleva a ninguna parte.
python
beautifulsoup
Cmag
fuente
fuente

Respuestas:
Aqui tienes:
data = [] table = soup.find('table', attrs={'class':'lineItemsTable'}) table_body = table.find('tbody') rows = table_body.find_all('tr') for row in rows: cols = row.find_all('td') cols = [ele.text.strip() for ele in cols] data.append([ele for ele in cols if ele]) # Get rid of empty valuesEsto te da:
[ [u'1359711259', u'SRF', u'08/05/2013', u'5310 4 AVE', u'K', u'19', u'125.00', u'$'], [u'7086775850', u'PAS', u'12/14/2013', u'3908 6th Ave', u'K', u'40', u'125.00', u'$'], [u'7355010165', u'OMT', u'12/14/2013', u'3908 6th Ave', u'K', u'40', u'145.00', u'$'], [u'4002488755', u'OMT', u'02/12/2014', u'NB 1ST AVE @ E 23RD ST', u'5', u'115.00', u'$'], [u'7913806837', u'OMT', u'03/03/2014', u'5015 4th Ave', u'K', u'46', u'115.00', u'$'], [u'5080015366', u'OMT', u'03/10/2014', u'EB 65TH ST @ 16TH AV E', u'7', u'50.00', u'$'], [u'7208770670', u'OMT', u'04/08/2014', u'333 15th St', u'K', u'70', u'65.00', u'$'], [u'$0.00\n\n\nPayment Amount:'] ]Un par de cosas a tener en cuenta:
fuente
rows = table_body.find_all('tr') AttributeError: 'NoneType' object has no attribute 'find_all'find_allconfindAlltable = soup.find('table', attrs={'class':'analysis'})no mostraba tbody allí, así que simplemente encontrar td y tr hizo el trabajo. Entonces, según yo, la causa del errorAttributeError: 'NoneType' object has no attribute 'find_all'es cuando pasamos una etiqueta o campo que no está en el html de la página.Resuelto, así es como analiza sus resultados html:
table = soup.find("table", { "class" : "lineItemsTable" }) for row in table.findAll("tr"): cells = row.findAll("td") if len(cells) == 9: summons = cells[1].find(text=True) plateType = cells[2].find(text=True) vDate = cells[3].find(text=True) location = cells[4].find(text=True) borough = cells[5].find(text=True) vCode = cells[6].find(text=True) amount = cells[7].find(text=True) print amountfuente
Actualización: 2020
Si un programador está interesado solo en analizar la tabla de la página web, puede utilizar el método pandas
pandas.read_html.Digamos que queremos extraer la tabla de datos del PIB del sitio web: https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries
Luego, los siguientes códigos hacen el trabajo a la perfección (sin necesidad de una sopa hermosa y un html elegante):
import pandas as pd import requests url = "https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries" r = requests.get(url) df_list = pd.read_html(r.text) # this parses all the tables in webpages to a list df = df_list[0] df.head()Salida
fuente
Aquí hay un ejemplo de trabajo para un genérico
<table>. ( enlaces de preguntas rotos )Extrayendo la tabla de aquí países por PIB (Producto Interno Bruto).
htmltable = soup.find('table', { 'class' : 'table table-striped' }) # where the dictionary specify unique attributes for the 'table' tagLa
tableDataTextfunción analiza un segmento html iniciado con una etiqueta<table>seguida de varias<tr>(filas de tabla) y<td>etiquetas internas (datos de tabla). Devuelve una lista de filas con columnas internas. Acepta solo uno<th>(encabezado / datos de la tabla) en la primera fila.def tableDataText(table): rows = [] trs = table.find_all('tr') headerow = [td.get_text(strip=True) for td in trs[0].find_all('th')] # header row if headerow: # if there is a header row include first rows.append(headerow) trs = trs[1:] for tr in trs: # for every table row rows.append([td.get_text(strip=True) for td in tr.find_all('td')]) # data row return rowsUsándolo obtenemos (primeras dos filas).
list_table = tableDataText(htmltable) list_table[:2] [['Rank', 'Name', "GDP (IMF '19)", "GDP (UN '16)", 'GDP Per Capita', '2019 Population'], ['1', 'United States', '21.41 trillion', '18.62 trillion', '$65,064', '329,064,917']]Eso se puede transformar fácilmente en
pandas.DataFrameherramientas más avanzadas.import pandas as pd dftable = pd.DataFrame(list_table[1:], columns=list_table[0]) dftable.head(4)fuente