【问题标题】:How to use Python's HTMLParser to extract specific links如何使用 Python HTML Parser 提取特定链接
【发布时间】:2012-03-30 11:42:10
【问题描述】:

我一直在使用 HTMLParser 类在 Python 中开发一个基本的网络爬虫。我使用修改后的 handle_starttag 方法获取链接,如下所示:

def handle_starttag(self, tag, attrs):
    if tag == 'a':
        for (key, value) in attrs:
            if key == 'href':
                newUrl = urljoin(self.baseUrl, value)
                self.links = self.links + [newUrl]

当我想找到页面上的每个链接时,这非常有效。现在我只想获取某些链接。

我将如何只获取<td class="title"></td> 标签之间的链接,如下所示:

<td class="title"><a href="http://www.stackoverflow.com">StackOverflow</a><span class="comhead"> (arstechnica.com) </span></td>

【问题讨论】:

  • 检查标签是否有一个类名为title的父级!
  • 你如何推荐这样做?
  • 你检查过 Python lxml 库吗?它可以非常有效地解析页面上的链接和其他元素。 lxml.de
  • 不,我没有,我去看看。不过,必须有一种方法可以使用 HTMLParser 类。我似乎在任何地方都找不到有关 handle_starttag 方法的太多信息。
  • 我会使用 beautifulsoup :) 你想让我在 BeautifulSoup 上发布解决方案吗?

标签: python parsing hyperlink web-crawler html-parsing


【解决方案1】:

HTMLParser 是一种 SAX 样式或流式解析器,这意味着您可以在解析文档时获得部分文档,但不能一次获得整个文档。解析器调用您提供的方法来处理标签和其他类型的数据。您自己可能感兴趣的任何上下文,例如哪些标签在其他标签内,您必须从您看到经过的标签中收集。

例如,如果您看到&lt;td&gt; 标记,那么您就知道您在一个表格单元格中,并且可以设置一个标志来实现该效果。当您看到&lt;/td&gt; 时,您就知道您已经离开了一个表格单元格并且可以清除该标志。要获取表格单元格内的链接,如果您看到 &lt;a&gt; 并且您知道您在表格单元格中(因为您设置了该标志),则获取标记的 href 属性的值(如果它有)一个。

from HTMLParser import HTMLParser

class LinkExctractor(HTMLParser):

    def reset(self):
        HTMLParser.reset(self)
        self.extracting = False
        self.links      = []

    def handle_startag(self, tag, attrs):
        if tag == "td" or tag == "a":
            attrs = dict(attrs)   # save us from iterating over the attrs
        if tag == "td" and attrs.get("class", "") == "title":
            self.extracting = True
        elif tag == "a" and "href" in attrs and self.extracting:
            self.links.append(attrs["href"])

    def handle_endtag(self, tag):
        if tag == "td":
            self.extracting = False

这很快就会变得很痛苦,因为您需要越来越多的上下文才能从文档中获取所需的内容,这就是人们推荐 lxmlBeautifulSoup 的原因。这些是 DOM 样式的解析器,可为您跟踪文档层次结构并提供各种友好的导航方式,例如 DOM API、XPath 和/或 CSS 选择器。

顺便说一句,我最近回答了一个类似的问题here

【讨论】:

  • 如果我可以建议使用 dict(attr) 而不是愚蠢的 for 和其他帖子中的 if,我会投票两次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多