Python / BeautifulSoup解析HTML分数

时间:2013-03-03 21:10:16

标签: python parsing unicode beautifulsoup

问题

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

  2. 从分数到小数(-1.75),我最干净的方法是什么?

  3. 背景

    我正在使用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']
    

1 个答案:

答案 0 :(得分:2)

让我们先解决问题的简单部分:

打印列表时,内容的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'

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

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)

因此,我们现在有一个名为dict的{​​{1}},它将unicode代码点映射到分数的fraction十进制表示。

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)

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