漂亮汤,HTML 表格解析

4

我目前遇到了一个问题,尝试将表格解析为数组。

我有一个简单的表格(在这里),需要使用BS4进行解析,并将单元格内容放入一个数组中。使事情变得困难的是,单元格不包含文本,而是包含具有以下标题的图像: “Confirm”或“Site”-这仅是用户权限的问题。 [我跳过了包含复选框的第一行,这些可以轻松提取]

如果您查看上面的示例,我只需要以这样的方式解析它,即生成的数组变为:

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 explanations: rightml - 表格的soup。

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个回答

6
这样的东西是否可行:
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']

等我回家后再检查一下。但如果这个方法有效,你肯定可以拥有我所有的网络! - Meh

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

然后,一旦你有了一个名为User 1的命名元组实例,如user,你就可以...

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

我已经尝试过你的方法以及上面的那个,都能够很好地工作。非常感谢你的解释和建议! - Meh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接