python BeautifulSoup解析表


89

我正在学习pythonrequests和BeautifulSoup。为了进行练习,我选择编写一个快速的NYC停车票解析器。我能够得到一个非常丑陋的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 2014年

问题链接中断:下面是一个通用<table>的工作示例
eusoubrasileiro

Answers:


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您正在使用Beautiful Soup 4吗?
shaktimaan 2014年

1
替换find_allfindAll
user2314737 2014年

3
@ user2314737 BS支持驼峰式和下划线表示法。我使用的下划线与Python编码准则一致。
shaktimaan 2014年

2
好的,我解决了我的错误:在html的inspect视图中,它显示了tbody,但是,当我打印table = soup.find('table', attrs={'class':'analysis'})它的值时, 那里没有tbody,因此只需找到td和tr就可以了。因此,根据我的说法,导致错误的原因 AttributeError: 'NoneType' object has no attribute 'find_all'是当我们传递不在页面html中的标记或字段时。
Umesh Kaushik'4

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

假设我们要从以下网站提取GDP数据表:https//worldpopulationreview.com/countries/countries-by-gdp/#worldCountries

然后,以下代码可以完美地完成这项工作(不需要beautifulsoup和精美的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>。(问题链接已断开

此处按GDP(国内生产总值)国家/地区提取表格。

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

tableDataText函数解析以标记<table> 开头的html段,然后是多个<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)

熊猫DataFrame html表输出

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.