【问题标题】:Beautiful soup, html table parsing美汤,html表格解析
【发布时间】:2012-10-05 17:57:24
【问题描述】:

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

我有一个简单的表 (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的嵌套限制?请任何人看看,看看他们是否能找到这样做的方法?或者至少解释一下如何到达那里?

变量解释: 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)

我可以用这个代码离开..但我给了它在大学里的尝试。

【问题讨论】:

    标签: python beautifulsoup html-table html-parsing


    【解决方案1】:

    这样的工作是否可行:

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

    【讨论】:

    • 我回家后会检查。但如果这可行,你肯定可以拥有我所有的互联网!
    【解决方案2】:

    我认为这样对行使用列表理解会更快。

    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'
    

    【讨论】:

    • 我试过你的方法和上面的方法一样,都很好用。非常感谢您的解释和建议!
    猜你喜欢
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-29
    • 2012-02-05
    • 2022-10-20
    • 2017-09-29
    相关资源
    最近更新 更多