python BeautifulSoup解析表
Posted
技术标签:
【中文标题】python BeautifulSoup解析表【英文标题】:python BeautifulSoup parsing table 【发布时间】:2014-06-16 03:37:06 【问题描述】:我正在学习 python requests
和 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
并没有让我到任何地方。
【问题讨论】:
仔细阅读后,我实际上并不确定您的问题是什么。您能具体说明您需要帮助的部分吗? 问题链接断开:Bellow a working example 用于通用更新答案
如果程序员只对从网页中解析表格感兴趣,他们可以利用 pandas 方法pandas.read_html
。
假设我们要从网站上提取GDP数据表: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 年最好的方法! 仅当您已经在项目中的某处使用 pandas 时。一张表依赖太多 哈哈,你复制了我下面的示例并改进了答案。好吧,至少我喜欢知道 pandas 有这样的方法。不错! 是的,我曾经从您的示例中获取 GDP 的 URL。是的,如果您喜欢快速方法,我们可以简单地使用pd.read_html
,而不是整个请求和美丽汤。
登录只是为了支持这个答案。这确实为我节省了 100 行代码。【参考方案2】:
from behave import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
import pandas as pd
import requests
from bs4 import BeautifulSoup
from tabulate import tabulate
class readTableDataFromDB:
def LookupValueFromColumnSingleKey(context, tablexpath, rowName, columnName):
print("element present readData From Table")
element = context.driver.find_elements_by_xpath(tablexpath+"/descendant::th")
indexrow = 1
indexcolumn = 1
for values in element:
valuepresent = values.text
print("text present here::"+valuepresent+"rowName::"+rowName)
if valuepresent.find(columnName) != -1:
print("current row"+str(indexrow) +"value"+valuepresent)
break
else:
indexrow = indexrow+1
indexvalue = context.driver.find_elements_by_xpath(
tablexpath+"/descendant::tr/td[1]")
for valuescolumn in indexvalue:
valuepresentcolumn = valuescolumn.text
print("Team text present here::" +
valuepresentcolumn+"columnName::"+rowName)
print(indexcolumn)
if valuepresentcolumn.find(rowName) != -1:
print("current column"+str(indexcolumn) +
"value"+valuepresentcolumn)
break
else:
indexcolumn = indexcolumn+1
print("index column"+str(indexcolumn))
print(tablexpath +"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
#lookupelement = context.driver.find_element_by_xpath(tablexpath +"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
#print(lookupelement.text)
return context.driver.find_elements_by_xpath(tablexpath+"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
def LookupValueFromColumnTwoKeyssss(context, tablexpath, rowName, columnName, columnName1):
print("element present readData From Table")
element = context.driver.find_elements_by_xpath(
tablexpath+"/descendant::th")
indexrow = 1
indexcolumn = 1
indexcolumn1 = 1
for values in element:
valuepresent = values.text
print("text present here::"+valuepresent)
indexrow = indexrow+1
if valuepresent == columnName:
print("current row value"+str(indexrow)+"value"+valuepresent)
break
for values in element:
valuepresent = values.text
print("text present here::"+valuepresent)
indexrow = indexrow+1
if valuepresent.find(columnName1) != -1:
print("current row value"+str(indexrow)+"value"+valuepresent)
break
indexvalue = context.driver.find_elements_by_xpath(
tablexpath+"/descendant::tr/td[1]")
for valuescolumn in indexvalue:
valuepresentcolumn = valuescolumn.text
print("Team text present here::"+valuepresentcolumn)
print(indexcolumn)
indexcolumn = indexcolumn+1
if valuepresent.find(rowName) != -1:
print("current column"+str(indexcolumn) +
"value"+valuepresentcolumn)
break
print("indexrow"+str(indexrow))
print("index column"+str(indexcolumn))
lookupelement = context.driver.find_element_by_xpath(
tablexpath+"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
print(tablexpath +
"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
print(lookupelement.text)
return context.driver.find_element_by_xpath(tablexpath+"//descendant::tr["+str(indexrow)+"]/td["+str(indexcolumn)+"]")
【讨论】:
【参考方案3】:这是通用<table>
的工作示例。 (问题链接断开)
从here 个国家/地区按 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)
【讨论】:
是否可以访问此表中的列?如果是这样,该怎么做? eusoubrasileiro também 哈哈哈 我明白了!只需使用 .get("column_name") 伊索艾@Jaílton Silva De onde obteu o list_table?【参考方案4】:给你:
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。 每行的最后一列必须单独处理,因为它是一个输入文本框。【讨论】:
我想知道为什么它对你有用...我得到rows = table_body.find_all('tr') AttributeError: 'NoneType' object has no attribute 'find_all'
用findAll
替换find_all
@user2314737 BS 支持驼峰式和下划线表示法。我使用符合 Python 编码指南的下划线。
好的,我解决了我的错误:在检查 html 视图中,它显示 tbody,但是,当我打印 table = soup.find('table', attrs='class':'analysis')
的值时,那里没有显示 tbody,所以只需找到 td 和 tr 就可以了.所以根据我的说法,出现错误AttributeError: 'NoneType' object has no attribute 'find_all'
的原因是我们传递了一个不在页面 html 中的标签或字段。
如果您在检查视图时看到某些内容,但在树中找不到,请尝试将解析器更改为 lxml
或 html5lib
crummy.com/software/BeautifulSoup/bs4/doc/#parser-installation【参考方案5】:
已解决,这是您解析其 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
【讨论】:
非常感谢,它在一个充满 JS 的网站上非常适合我。以上是关于python BeautifulSoup解析表的主要内容,如果未能解决你的问题,请参考以下文章
如何使用Python中的BeautifulSoup从HTML链接解析嵌套表?
python 使用BeautifulSoup解析表的示例和Python中的请求
使用Python 3和beautifulsoup4解析HTML表