我正在尝试使用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的新手,所以请对我温柔!感谢
答案 0 :(得分: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)
答案 1 :(得分:3)
我认为上述答案比我提供的更好,但我有一个BeautifulSoup答案,可以帮助你入门。这有点hackish,但我想我会提供它。
使用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',所以你必须执行以下操作来捕获 next 值(你想要的第一个值):
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]
免责声明:最后一行对我来说非常难看。
答案 2 :(得分: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