【问题标题】:Please help parse this html table using BeautifulSoup and lxml the pythonic way请帮助使用 BeautifulSoup 和 lxml 以 pythonic 方式解析这个 html 表
【发布时间】:2011-06-13 06:25:14
【问题描述】:

我搜索了很多关于 BeautifulSoup 和一些建议 lxml 作为 BeautifulSoup 的未来,虽然这是有道理的,但我很难从网页上的整个表格列表中解析下表。

我对具有不同行数的三列感兴趣,具体取决于页面和检查时间。 BeautifulSoup 和 lxml 解决方案非常受欢迎。这样我可以要求管理员在开发人员上安装 lxml。机器。

期望的输出:

Website                    Last Visited          Last Loaded
http://google.com          01/14/2011 
http://stackoverflow.com   01/10/2011
...... more if present

以下是来自混乱网页的代码示例:

<table border="2" width="100%">
  <tbody><tr>
    <td width="33%" class="BoldTD">Website</td>
    <td width="33%" class="BoldTD">Last Visited</td>
    <td width="34%" class="BoldTD">Last Loaded</td>
  </tr>
  <tr>
    <td width="33%">
      <a href="http://google.com"</a>
    </td>
    <td width="33%">01/14/2011
            </td>
    <td width="34%">
            </td>
  </tr>
  <tr>
    <td width="33%">
      <a href="http://stackoverflow.com"</a>
    </td>
    <td width="33%">01/10/2011
            </td>
    <td width="34%">
            </td>
  </tr>
</tbody></table>

【问题讨论】:

  • 您想要什么结果?带有站点名称和日期的字典条目? html的来源是什么?它在你的控制范围内吗?
  • 不幸的是,html 的来源不在我的控制范围内。字典条目会起作用,只是没有。每页的行数不同,如“所需输出”部分所示。没有与表格关联的类,因此如果表格的内容中有“网站”,那么我们会抓取该数据。

标签: python beautifulsoup html-table lxml


【解决方案1】:
>>> from lxml import html
>>> table_html = """"
...         <table border="2" width="100%">
...                       <tbody><tr>
...                         <td width="33%" class="BoldTD">Website</td>
...                         <td width="33%" class="BoldTD">Last Visited</td>
...                         <td width="34%" class="BoldTD">Last Loaded</td>
...                       </tr>
...                       <tr>
...                         <td width="33%">
...                           <a href="http://google.com"</a>
...                         </td>
...                         <td width="33%">01/14/2011
...                                 </td>
...                         <td width="34%">
...                                 </td>
...                       </tr>
...                       <tr>
...                         <td width="33%">
...                           <a href="http://stackoverflow.com"</a>
...                         </td>
...                         <td width="33%">01/10/2011
...                                 </td>
...                         <td width="34%">
...                                 </td>
...                       </tr>
...                     </tbody></table>"""
>>> table = html.fromstring(table_html)
>>> for row in table.xpath('//table[@border="2" and @width="100%"]/tbody/tr'):
...     for column in row.xpath('./td[position()=1]/a/@href | ./td[position()>1]/text() | self::node()[position()=1]/td/text()'):
...             print column.strip(),
...     print
... 
Website Last Visited Last Loaded
 http://google.com 01/14/2011 
 http://stackoverflow.com 01/10/2011 
>>> 

瞧;) 当然,您可以将值添加到嵌套列表或字典中,而不是打印;)

【讨论】:

  • 感谢 lxml 实现!我还没有检查它,因为我们的机器上还没有安装 lxml。管理员必须这样做,所以等待:(我们可以将此代码转换为 BeautifulSoup 以便快速检查吗?
  • 小错字:更改 'table = lxml.fromstring(table_html)' 和 'table = html.fromstring(table_html)' 即可运行。
  • 您可以使用 ElementTree etree 实现(您可以通过 easy_install 或 pip 轻松安装)来测试它,但我不确定它是否支持完整的 xpath 语法。
  • HTML 中有一个错误('google.com"</a>' 应该是 'google.com"></a>' )但奇怪的是,lxml 可以,但是ElementTree 不是。
  • 在 centOS 上安装 lxml 被证明是一个挑战 :(
【解决方案2】:

这是一个使用 elementtree 及其提供的有限 XPath 的版本:

from xml.etree.ElementTree import ElementTree

doc = ElementTree().parse('table.html')

for t in doc.findall('.//table'):
  # there may be multiple tables, check we have the right one
  if t.find('./tbody/tr/td').text == 'Website':
    for tr in t.findall('./tbody/tr/')[1:]: # skip the header row
      tds = tr.findall('./td')
      print tds[0][0].attrib['href'], tds[1].text.strip(), tds[2].text.strip()

结果:

http://google.com 01/14/2011
http://stackoverflow.com 01/10/2011 

【讨论】:

  • 我得到这个错误:doc = ElementTree().parse('test.htm') File "/usr/local/Python2.6/lib/python2.6/xml/etree/ElementTree. py”,第 586 行,解析 parser.feed(data) 文件“/usr/local/Python2.6/lib/python2.6/xml/etree/ElementTree.py”,第 1245 行,在提要 self._parser.Parse (数据,0)xml.parsers.expat.ExpatError:语法错误:第 2 行,第 61 列
  • 它在抱怨您的 xml.. 第 2 行第 61 列。您要发布该文件的第一行吗?在这里还是在粘贴箱中?
  • 嗯,看起来它正在寻找严格、格式良好的文本?pastebin.com/8BZQyB3b
  • 两个问题:你在 Windows 上吗?这是完整的文件吗?
  • 我在 centOS 上。不,这不是完整的文件,这里是:pastebin.com/tu7dfeRJ
【解决方案3】:

这是一个使用 HTMLParser 的版本。我尝试了 pastebin.com/tu7dfeRJ 的内容。它处理元标记和 doctype 声明,这两者都挫败了 ElementTree 版本。

from HTMLParser import HTMLParser

class MyParser(HTMLParser):
  def __init__(self):
    HTMLParser.__init__(self)
    self.line = ""
    self.in_tr = False
    self.in_table = False

  def handle_starttag(self, tag, attrs):
    if self.in_table and tag == "tr":
      self.line = ""
      self.in_tr = True
    if tag=='a':
     for attr in attrs:
       if attr[0] == 'href':
         self.line += attr[1] + " "

  def handle_endtag(self, tag):
    if tag == 'tr':
      self.in_tr = False
      if len(self.line):
        print self.line
    elif tag == "table":
      self.in_table = False

  def handle_data(self, data):
    if data == "Website":
      self.in_table = 1
    elif self.in_tr:
      data = data.strip()
      if data:
        self.line += data.strip() + " "

if __name__ == '__main__':
  myp = MyParser()
  myp.feed(open('table.html').read())

希望这能解决您所需要的一切,并且您可以接受这个作为答案。 按要求更新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-12
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 2015-02-16
    • 2010-10-10
    • 1970-01-01
    • 2014-05-17
    相关资源
    最近更新 更多