【问题标题】:Python/BeautifulSoup Parsing HTML FractionsPython/BeautifulSoup 解析 HTML 分数
【发布时间】:2013-03-03 21:10:15
【问题描述】:

问题

  1. 为什么最后两种情况下的输出都是 unicode,但在一种情况下显示分数,在另一种情况下显示表示分数的其他代码?

  2. 对我来说,从分数到小数 (-1.75) 的最简洁方法是什么?

背景

我正在使用BeautifulSoupPython 读取一些HTML. HTML 输出分数。下面是我用来测试这个问题的 python 代码,以及结果输出。在下面的代码中我有

print type(c[0])
print c[0]
print type(c[0].get_text())
print c[0].get_text()
print type(re.split(" ", c[0].get_text())[0])
print re.split(" ", c[0].get_text())

这个输出:

<class 'bs4.element.Tag'>
<b>-1¾ -101</b>
<type 'unicode'>
-1¾ -101
<type 'unicode'>
[u'-1\xbe\xa0-101']

【问题讨论】:

    标签: python parsing unicode beautifulsoup


    【解决方案1】:

    让我们先把你问题的简单部分排除在外:

    打印列表时,内容的repr 用于表示列表中的项目。所以自从

    re.split(" ", c[0].get_text())
    

    是一个列表,print语句打印列表中unicode元素的repr

    In [63]: x = u'-1\xbe\xa0-101'
    
    In [64]: print(x)
    -1¾ -101
    
    In [65]: repr(x)
    Out[65]: "u'-1\\xbe\\xa0-101'"
    

    现在是有趣的部分:一些 unicode 代码点有名称。 例如,

    In [60]: import unicodedata as ud
    
    In [61]: ud.name(u'\xbe')
    Out[61]: 'VULGAR FRACTION THREE QUARTERS'
    

    事实上,我们可以在所有 unicode 字符中搜索名称与'FRACTION (\w+) (\w+)' 模式匹配的字符:

    import unicodedata as ud
    import re
    
    numerator = {
        'ONE':1,
        'TWO':2,
        'THREE':3,
        'FOUR':4,
        'FIVE':5,
        'SIX':6,
        'SEVEN':7,
        'EIGHT':8,
        'NINE':9,
        'ZERO':0,
        }
    
    denominator = {
        'QUARTER':4,
        'HALF':2,
        'SEVENTH':7,
        'NINTH':9,
        'THIRD':3,
        'FIFTH':5,
        'SIXTH':6,
        'EIGHTH':8,
        'SIXTEENTH':16
        }
    
    fraction = {}
    for num in range(0x110000):
        s = unichr(num)
        try:
            name = ud.name(s)
        except ValueError:
            continue
        match = re.search('FRACTION ({n}) ({d})'.format(
            n = '|'.join(numerator.keys()),
            d = '|'.join(denominator.keys()),
            ) , name)
        if match:
            fraction[num] = unicode(
               float(numerator[match.group(1)])/denominator[match.group(2)]).lstrip('0')
    print(fraction)
    

    因此,我们现在有一个名为 fractiondict,它将 unicode 代码点映射到分数的十进制表示形式 unicode

    {8585: u'.0', 43056: u'.25', 43057: u'.5', 43058: u'.75', 43059: u'.0625', 43060: u'.125', 43061: u'.1875', 188: u'.25', 189: u'.5', 190: u'.75', 8528: u'.142857142857', 8529: u'.111111111111', 8531: u'.333333333333', 8532: u'.666666666667', 8533: u'.2', 8534: u'.4', 8535: u'.6', 8536: u'.8', 8537: u'.166666666667', 8538: u'.833333333333', 8539: u'.125', 8540: u'.375', 8541: u'.625', 8542: u'.875', 69245: u'.333333333333', 3443: u'.25', 3444: u'.5', 3445: u'.75', 69243: u'.5', 69244: u'.25', 11517: u'.5', 69246: u'.666666666667'}
    

    现在你可以像这样翻译u'-1\xbe\xa0-101'

    text = u'-1\xbe\xa0-101'
    print(text.translate(fraction))    
    

    产量

    -1.75 -101
    

    所以简短的回答是:

    fraction = {8585: u'.0', 43056: u'.25', 43057: u'.5', 43058: u'.75', 43059: u'.0625', 43060: u'.125', 43061: u'.1875', 188: u'.25', 189: u'.5', 190: u'.75', 8528: u'.142857142857', 8529: u'.111111111111', 8531: u'.333333333333', 8532: u'.666666666667', 8533: u'.2', 8534: u'.4', 8535: u'.6', 8536: u'.8', 8537: u'.166666666667', 8538: u'.833333333333', 8539: u'.125', 8540: u'.375', 8541: u'.625', 8542: u'.875', 69245: u'.333333333333', 3443: u'.25', 3444: u'.5', 3445: u'.75', 69243: u'.5', 69244: u'.25', 11517: u'.5', 69246: u'.666666666667'}
    text = c[0].get_text()
    text = text.translate(fraction)
    parts = map(float, text.split())
    print(parts)
    

    产量

    [-1.75, -101.0]
    

    请注意,将来可能会为更多的分数分配 unicode 代码点。也有可能 unicode 代码点的名称与我用来生成 fraction dict 的模式 'FRACTION ({n}) ({d})' 不匹配。所以我的解决方案有些脆弱,未来可能需要更新。

    【讨论】:

    • unutbu 非常感谢您的回复。我很惊讶没有图书馆或已经为这个问题创建的东西。我只是 n00bie 程序员,所以我需要一段时间才能完成您的回答,这很酷,我正在从您的编程技术中学习。
    • 如果您有任何问题,我会尽量详细说明。
    猜你喜欢
    • 2020-02-06
    • 2014-03-06
    • 2011-07-21
    • 2018-07-10
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多