python BeautifulSoup синтаксичний аналіз таблиці


89

Я вивчаю python requestsта BeautifulSoup. Для вправи я вирішив написати короткий аналізатор квитків на паркування в Нью-Йорку. Я можу отримати відповідь html, яка є досить потворною. Мені потрібно взяти lineItemsTableта проаналізувати всі квитки.

Ви можете відтворити сторінку, перейшовши сюди: https://paydirect.link2gov.com/NYCParking-Plate/ItemSearchі ввевши NYтабличкуT630134C

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

Хтось може допомогти мені? Простий пошук всього trмене нікуди не діває.


Якщо ближче прочитати, я насправді не впевнений, у чому ваше питання. Чи можете ви точно пояснити, з якою частиною вам потрібна допомога?
TML

посилання на запитання-порушено: Наведіть робочий приклад для загальної <таблиці>.
eusoubrasileiro

Відповіді:


171

Ось:

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 values

Це дає вам:

[ [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:']
]

Кілька речей, які слід зазначити:

  • Останній рядок у вихідних даних Сума платежу не є частиною таблиці, але саме так таблиця викладена. Ви можете відфільтрувати його, перевіривши, чи довжина списку менше 7.
  • Останній стовпець кожного рядка повинен оброблятися окремо, оскільки це текстове поле введення.

5
Мені цікаво, чому це працює у вас ... Я розуміюrows = table_body.find_all('tr') AttributeError: 'NoneType' object has no attribute 'find_all'
Cmag

@Cmag Ви використовуєте Beautiful Soup 4?
shaktimaan

1
Замінити find_allнаfindAll
user2314737

3
@ user2314737 BS підтримує як випадки верблюда, так і символи підкреслення. Я використовую підкреслення, що відповідає правилам кодування Python.
shaktimaan

2
Гаразд, я вирішив свою помилку: у режимі інспекції html він показує tbody, однак, коли я надрукував значення, table = soup.find('table', attrs={'class':'analysis'})там не було нікого, тому просто пошук td і tr зробив роботу. Отже, за моїми словами, причина помилки AttributeError: 'NoneType' object has no attribute 'find_all'полягає в тому, що ми передаємо тег або поле, якого немає в html сторінки.
Умеш Каушик,

23

Вирішено, ось як ваші аналізують свої результати 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 amount

14

Оновлення: 2020

Якщо програміст зацікавлений лише в аналізі таблиці з веб-сторінки, він може використовувати метод pandas pandas.read_html.

Скажімо, ми хочемо витягти таблицю даних ВВП з веб-сайту: https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries

Тоді наступні коди чудово справляються з цією роботою (Не потрібно красивої супи та вишуканого html):

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()

Вихідні дані

Перші п’ять рядків таблиці з веб-сайту


Погоджено - це явно найкращий підхід на 2020 рік!
kfmfe04

1
Тільки якщо ви вже використовуєте панди десь у своєму проекті. Занадто багато залежностей для однієї таблиці
Сергей Яхницкий

3

Ось робочий приклад для загального <table>. ( посилання на запитання порушено )

Витяг таблиці звідси країн за ВВП (валовий внутрішній продукт).

htmltable = soup.find('table', { 'class' : 'table table-striped' })
# where the dictionary specify unique attributes for the 'table' tag

tableDataTextФункція аналізує HTML - сегмент почав з тегом , <table> потім кілька <tr>(рядками таблиці) і внутрішніми <td>тегами (таблиця даних). Він повертає список рядків із внутрішніми стовпцями. Приймає лише один <th>(заголовок / дані таблиці) у першому рядку.

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 rows

З його допомогою отримуємо (перші два ряди).

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']]

Це можна легко перетворити pandas.DataFrameна додаткові інструменти.

import pandas as pd
dftable = pd.DataFrame(list_table[1:], columns=list_table[0])
dftable.head(4)

pandas DataFrame html вихід таблиці

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.