美丽的汤,html表解析

时间:2012-10-15 17:41:01

标签: python beautifulsoup html-table html-parsing

我目前在尝试将表解析为数组时遇到了一些问题。

我有一个简单的表(HERE),我需要用BS4解析并将单元格内容放入数组中。这里的困难之处在于细胞不包含文本,而是具有这些标题的图像: “确认”或“网站” - 这只是用户权利的东西。 [我正在跳过包含复选框的第一行,我可以毫无问题地提取这些复选框]

如果你看一下上面的小提琴,我需要做的就是以这样的方式解析它:结果数组变成:

Array1[0] = User1,Confirm,Confirm,Site,Confirm
Array1[1] = User2,Confirm,Confirm,Confirm,Confirm
Array1[2] = User3,Confirm,Confirm,Confirm,Confirm
Array1[3] = User4,Confirm,Site,Site,Confirm

然后我可以随心所欲地做。 另一个复杂因素是,有时行数会有所不同,因此脚本应该能够适应这种情况,并从表中递归创建数组。

目前StackOverflow是我唯一的希望..我在过去的10个小时里一直在做这件事,几乎没有成功,坦率地说,我已经失去了希望。最接近我得到的东西是在封闭的标签中提取,但由于一些奇怪的原因无法进一步解析,也许这是bs4的嵌套限制?任何人都可以看看,看看他们是否能找到这样做的方法?或至少解释如何到达那里?

var解释: rightml - 桌上的汤。

allusers = []
rows = rightml.findAll('tr')
for tr in rows:
    cols = tr.findAll('td')
    for td in cols:
        if (td.find(title="Group")) or (td.find(title="User")):
            text = ''.join(td.text.strip())
            allusers.append(text)
print allusers

gifrights = []

rows7 = rightml.findAll('td')
#print rows7
for tr7 in rows:
    cols7 = tr7.findAll('img')
    for td7 in cols7:
        if (td7.find(title="Confirm")) or (td7.find(title="Site")):
            text = ''.join(td7.text.strip())
            text2 = text.split(' ')
            print text2
            gifrights.append(text2)

我可以用这段代码解决问题..但是我给了它'大学尝试。

2 个答案:

答案 0 :(得分:5)

这样的事情会起作用吗?

rows = soup.find('tbody').findAll('tr')

for row in rows:
    cells = row.findAll('td')

    output = []

    for i, cell in enumerate(cells):
        if i == 0:
            output.append(cell.text.strip())
        elif cell.find('img'):
            output.append(cell.find('img')['title'])
        elif cell.find('input'):
            output.append(cell.find('input')['value'])
    print output

这输出以下内容:

[u'Logged-in users', u'True', u'True', u'True', u'True']
[u'User 1', u'Confirm', u'Confirm', u'Site', u'Confirm']
[u'User 2', u'Confirm', u'Confirm', u'Confirm', u'Confirm']
[u'User 3', u'Confirm', u'Confirm', u'Confirm', u'Confirm']
[u'User 4', u'Confirm', u'Site', u'Site', u'Confirm']

答案 1 :(得分:4)

我认为在行上使用列表理解会更快。

rows = soup.find('tbody').findAll('tr')

for i in rows[1:]: # the first row is thrown out
    [j['title'] for j in i.findAll('img')]

哪个给你

['User', 'Confirm', 'Confirm', 'Site', 'Confirm']
['User', 'Confirm', 'Confirm', 'Confirm', 'Confirm']
['User', 'Confirm', 'Confirm', 'Confirm', 'Confirm']
['User', 'Confirm', 'Site', 'Site', 'Confirm']

您可以使用嵌套列表理解来删除更多步骤:

# superpythonic
[[j['title'] for j in i.findAll('img')] for i in rows[1:]]

# all together now, but not so pythonic
[[j['title'] for j in i.findAll('img')] for i in soup.find('tbody').findAll('tr')[1:]]

你真的不需要用户#,因为用户#是索引号+1。

[[j['title'] for j in i.findAll('img') if j['title'] != 'User'] for i in rows[1:]]

但是,如果你 - 必须有一个......

for i in xrange(len(users)):
    users[i].append("User " + str(i+1))

但是,如果你坚持这样做,我会使用namedtuple作为数据结构而不是列表。 namedtuple

from collections import namedtuple
# make these actual non-obfuscated names, not column numbers
User = namedtuple('User', ('num col_1 col_2 col_3 col_4') 

然后,一旦你有一个namedtuple实例,比如用户1为user,你就可以......

>>> user.num
... 1
>>> user.col_1
... 'Confirm'
>>> user.col_2
... 'Confirm'
>>> user.col_3
... 'Site'
>>> user.col_4
... 'Confirm'