使用损坏的HTML + BeautifulSoup

时间:2018-01-20 04:28:11

标签: python python-3.x beautifulsoup

我有一些非常糟糕的HTML,长话短说,阻止我使用普通的嵌套<table>, <tr>, <td>结构,这样可以很容易地重建表格。

这是一个带行号的片段供参考:

1      <td valign="top">   <!-- closing </td> should be on 6 -->
2      <font face="arial" size="1">
3       <center>
4        06-30-95
5       </center>
6       <tr valign="top">
7        <td>
8         <center>
9          <font ,="" arial,="" face="arial" sans="" serif"="" size="1">
10          1382
11          <p>
12           (23)
13          </p>
14         </font>
15        </center>
16       </td>
17       <td>
18        <font ,="" arial,="" face="arial" sans="" serif"="" size="1">
19         <center>
20          06-18-14
21         </center>
22        </font>
23       </td>
24      </tr>
25    </td>    <!-- this should should be on 6 -->

trtd s内tr s的嵌套没有任何方案,并且与未关闭的标签相关联以进行引导。 HTML树绝不像它在结构上呈现的方式。 (在这种情况下,我认为技术上没有缺少结束标记,但页面的实际呈现表明应该没有嵌套的td。)

但是,在这种情况下,按照以下规则进行播放

  • 对于在结束<td>之前有一个开头<td>的任何</td>,(即任何嵌套的td)都假设后者开放<td> (第7行)作为第一行(第1行)的闭包;
  • 否则,就像往常一样抓住(打开,关闭)<td> ... </td>标签(开启者和附近人员之间没有<td>;例如上面的第17和23行。

这里的期望结果将是:

['06-30-95', '1382\n(23)', '06-18-14']

如何在BeautifulSoup中解决这个问题?我会展示一个尝试,但已经选择了文档和一些来源,但根本没有找到。

目前,这将解析为:

html = """
<td valign="top">
 <font face="arial" size="1">
  <center>
   06-30-95
  </center>
  <tr valign="top">
   <td>
    <center>
     <font ,="" arial,="" face="arial" sans="" serif"="" size="1">
      1382
      <p>
       (23)
      </p>
     </font>
    </center>
   </td>
   <td>
    <font ,="" arial,="" face="arial" sans="" serif"="" size="1">
     <center>
      06-18-14
     </center>
    </font>
   </td>
  </tr>
</td>
"""

from bs4 import BeautifulSoup, SoupStrainer

strainer = SoupStrainer('td')
soup = BeautifulSoup(html, 'html.parser', parse_only=strainer)
[tag.text.replace('\n', '') for tag in soup.find_all('td')]

['   06-30-95        1382             (23)            06-18-14     ',
 '      1382             (23)      ',
 '      06-18-14     ']

我对这个结果的问题不是空白;它是子串的重复。看起来我似乎需要递归地从最里面的标签向上工作,弹出每个标签并向外工作。但我必须猜测还有更多内置功能来处理缺少的结束标记(handle_endtagBeautifulSoup构造函数中脱颖而出?)。

2 个答案:

答案 0 :(得分:2)

对于非常破碎的HTML,有两种方法可以解决这个问题。首先是在最里面的嵌套级别找到最一致的打开/关闭标签集,并且只使用第一个。在这个有限的示例中,只要>>> from bs4 import BeautifulSoup >>> soup = BeautifulSoup(html, 'html.parser') >>> [t.find('center').text.strip() for t in soup.find_all('td')] ['06-30-95', '1382\n \n (23)', '06-18-14'] 标签满足此要求即可。请考虑以下事项:

lxml

或者,使用>>> soup2 = BeautifulSoup(html, 'lxml') >>> [t.text.strip() for t in soup2.find_all('td')] ['06-30-95', '1382\n \n (23)', '06-18-14'] 代替(作为方法列出的Gulp Error)实际上可以更好地整体运作:

{{1}}

此主题涵盖了其他方法:documentation

答案 1 :(得分:2)

试试这个。它会获取您请求的输出:

from bs4 import BeautifulSoup

soup = BeautifulSoup(content, 'html5lib')
item = [' '.join(items.text.split()) for items in soup.select("center")]
print(item)

输出:

['06-30-95', '1382 (23)', '06-18-14']