5

我正在尝试使用 BeautifulSoup 解析我上传到http://pastie.org/8070879的 html 表,以便将三列(0 到 735、0.50 到 1.0 和 0.5 到 0.0)作为列表。为了解释原因,我希望整数 0-735 是键,十进制数是值。

通过阅读 SO 上的许多其他帖子,我想出了以下内容,这些内容与创建我想要的列表并不接近。它所做的只是在表格中显示文本,如下所示http://i1285.photobucket.com/albums/a592/TheNexulo/output_zps20c5afb8.png

from bs4 import BeautifulSoup

soup = BeautifulSoup(open("fide.html"))
table = soup.find('table')

rows = table.findAll('tr')

for tr in rows:
  cols = tr.findAll('td')
  for td in cols:
     text = ''.join(td.find(text=True))
     print text + "|",
  print 

我是 Python 和 BeautifulSoup 的新手,所以请对我温柔一点!谢谢

4

3 回答 3

3

我认为上面的答案比我提供的要好,但我有一个 BeautifulSoup 答案可以让你开始。这有点骇人听闻,但我想我还是会提供它。

使用 BeautifulSoup,您可以通过以下方式找到具有特定属性的所有标签(假设您已经设置了一个 soup.object):

soup.find_all('td', attrs={'bgcolor':'#FFFFCC'})

这将找到你所有的钥匙。诀窍是将这些与您想要的值相关联,这些值随后都会立即显示并且成对出现(如果这些事情发生变化,顺便说一下,这个解决方案将不起作用)。

因此,您可以尝试以下操作来访问您的关键条目之后的内容并将其放入 your_dictionary:

 for node in soup.find_all('td', attrs={'bgcolor':'#FFFFCC'}):
   your_dictionary[node.string] = node.next_sibling

问题是“next_sibling”实际上是一个'\n',所以你必须执行以下操作来捕获下一个值(你想要的第一个值):

for node in soup.find_all('td', attrs={'bgcolor':'#FFFFCC'}):
  your_dictionary[node.string] = node.next_sibling.next_sibling.string

如果您想要以下两个值,则必须将其加倍:

for node in soup.find_all('td', attrs={'bgcolor':'#FFFFCC'}):
  your_dictionary[node.string] = [node.next_sibling.next_sibling.string, node.next_sibling.next_sibling.next_sibling.next_sibling.string]

免责声明:最后一行对我来说非常难看。

于 2013-06-23T02:38:42.513 回答
3

像 BeautifulSoup 这样的 HTML 解析器假定您想要的是一个反映输入 HTML 结构的对象模型。但有时(例如在这种情况下)该模型会阻碍而不是帮助。Pyparsing 包括一些 HTML 解析功能,这些功能比仅使用原始正则表达式更强大,但以类似的方式工作,让您定义感兴趣的 HTML 片段,而忽略其余部分。这是一个解析器,它会读取您发布的 HTML 源代码:

from pyparsing import makeHTMLTags,withAttribute,Suppress,Regex,Group

""" looking for this recurring pattern:
          <td valign="top" bgcolor="#FFFFCC">00-03</td>
          <td valign="top">.50</td>
          <td valign="top">.50</td>

    and want a dict with keys 0, 1, 2, and 3 all with values (.50,.50)
"""

td,tdend = makeHTMLTags("td")
keytd = td.copy().setParseAction(withAttribute(bgcolor="#FFFFCC"))
td,tdend,keytd = map(Suppress,(td,tdend,keytd))

realnum = Regex(r'1?\.\d+').setParseAction(lambda t:float(t[0]))
integer = Regex(r'\d{1,3}').setParseAction(lambda t:int(t[0]))
DASH = Suppress('-')

# build up an expression matching the HTML bits above
entryExpr = (keytd + integer("start") + DASH + integer("end") + tdend + 
                    Group(2*(td + realnum + tdend))("vals"))

这个解析器不仅挑选出匹配的三元组,它还提取起始整数和实数对(并且在解析时已经从字符串转换为整数或浮点数)。

看一下表格,我猜你实际上想要一个查找,它需要像 700 这样的键,并返回一对值 (0.99, 0.01),因为 700 落在 620-735 的范围内。这段代码搜索源 HTML 文本,遍历匹配的条目并将键值对插入到 dict 查找中:

# search the input HTML for matches to the entryExpr expression, and build up lookup dict
lookup = {}
for entry in entryExpr.searchString(sourcehtml):
    for i in range(entry.start, entry.end+1):
        lookup[i] = tuple(entry.vals)

现在尝试一些查找:

# print out some test values
for test in (0,20,100,700):
    print (test, lookup[test])

印刷:

0 (0.5, 0.5)
20 (0.53, 0.47)
100 (0.64, 0.36)
700 (0.99, 0.01)
于 2013-06-23T02:20:44.867 回答
0

我用过 BeautifulSoup 3,但它可能会在 4 下工作。

# Import System libraries
import re

# Import Custom libraries
from BeautifulSoup import BeautifulSoup

# This may be different between BeautifulSoup 3 and BeautifulSoup 4
with open("fide.html") as file_h:
    # Read the file into the BeautifulSoup class
    soup = BeautifulSoup(file_h.read())

tr_location = lambda x: x.name == u"tr" # Row location
key_location = lambda x: x.name == u"td" and bool(set([(u"bgcolor", u"#FFFFCC")]) & set(x.attrs)) # Integer key location
td_location = lambda x: x.name == u"td" and not dict(x.attrs).has_key(u"bgcolor") # Float value location

str_key_dict = {}
num_key_dict = {}
for tr in soup.findAll(tr_location): # Loop through all found rows
    for key in tr.findAll(key_location): # Loop through all found Integer key tds
        key_list = []
        key_str = key.text.strip()
        for td in key.findNextSiblings(td_location)[:2]: # Loop through the next 2 neighbouring Float values
            key_list.append(td.text)
        key_list = map(float, key_list) # Convert the text values to floats

        # String based dictionary section
        str_key_dict[key_str] = key_list

        # Number based dictionary section
        num_range = map(int, re.split("\s*-\s*", key_str)) # Extract a value range to perform interpolation
        if(len(num_range) == 2):
            num_key_dict.update([(x, key_list) for x in range(num_range[0], num_range[1] + 1)])
        else:
            num_key_dict.update([(num_range[0], key_list)])

for x in num_key_dict.items():
    print x
于 2013-06-23T03:29:06.173 回答