查找包含给定单词的最大提及次数的HTML元素

时间:2012-11-12 15:21:52

标签: python html dom html-parsing cluster-analysis

我有一个HTML文档,我想找到HTML元素,它是最接近给定单词的最大提及集合的包装器。

使用以下HTML:

<body>
    <p>
        Hello <b>foo</b>, I like foo, because foo is the best.
    <p>
    <div>
        <blockquote>
            <p><strong>Foo</strong> said: foo foo!</p>
            <p>Smurfs ate the last foo and turned blue. Foo!</p>
            <p>Foo foo.</p>
        </blockquote>
    </div>
</body>

我想要一个功能

find_largest_cluster_wrapper(html, word='foo')

...它将解析DOM树并返回<blockquote>元素,因为它包含 foo 提及的最大密度,它是最接近的包装器。

第一个<p>包含 foo 3次,<b>只包含一次,内部<p>包含 foo 3次,两次和两次,<strong>只有一次。但<blockquote>包含 foo 4次。 <div>也是如此,但它不是最接近的包装器。 <body>元素的提及次数最多,但它太稀疏了。

没有聚类的直接实现会给我总是<html><body>或类似的东西,因为这些元素总是具有最大数量的请求提及,并且可能是最接近它们的包装器。但是,我需要采用最大群集的东西,因为我只对网页中密度最高的部分感兴趣。

我对解析部分不是很好奇,beautifulsoup4或其他库可以很好地解决它。我想知道一个有效的算法来进行聚类。我用谷歌搜索了一段时间,我认为scipy中的clustering package可能会有所帮助,但我不知道如何使用它。有人能推荐我最好的解决方案,并把我踢向正确的方向吗?例子非常棒。


嗯,一般来说很难回答这个问题,因为正如你所指出的那样,条件是模糊的。所以,更具体地说:

通常,文档可能只包含一个此类群集。我的目的是找到这样的集群,并获得它的包装,以便我可以使用它进行操作。这个词也可以在页面的其他地方提到,但我正在寻找一个值得注意的这样的词汇集群。如果有两个值得注意的集群或更多,那么我必须使用外部偏差来决定(检查标题,页面标题等)。这个群集值得注意的是什么意思?这恰恰意味着我刚才提出的 - 没有“严肃”的竞争对手。如果竞争对手是否严重,我可以提供一些数量(比例),例如:如果有10个簇和2个簇,则差异为80%。我可以说如果有一个差异大于50%的集群,那将是值得注意的集群。这意味着,如果它是5的簇和5的另一个,该函数将返回None(无法决定)。

3 个答案:

答案 0 :(得分:3)

所以这是一种方法:

|fitness(node, word) = count of word in node text if node is a leaf
|fitness(node, word) = sum(fitness(child, word) for child in children) / 
                         count of overall elements in node tree

这是:

import lxml.html

node = """<html><body>
    <p>
        Hello <b>foo</b>, I like foo, because foo is the best.
    <p>
    <div>
        <blockquote>
            <p><strong>Foo</strong> said: foo foo!</p>
            <p>Smurfs ate the last foo and turned blue. Foo!</p>
            <p>Foo foo.</p>
        </blockquote>
    </div>
</body></html>"""

node = lxml.html.fromstring(node)

def suitability(node, word):
    mx = [0.0, None]
    _suitability(node, word, mx)
    return mx[1]

def _suitability(node, word, mx):

    children = node.getchildren()
    sparsity = 1
    result = float(node.text_content().lower().count(word))
    for child in children:
        res, spars = _suitability(child, word, mx)
        result += res
        sparsity += spars
    result /= sparsity
    current_max, max_node = mx
    if current_max < result:
        mx[0] = result
        mx[1] = node
    return result, sparsity

print suitability(node, 'foo')

它给我们块引用元素作为最适合的。通过调整分数功能,您可以更改所需群集的参数。

答案 1 :(得分:1)

所以这不是一个图书馆,但我有一个想法。

如果您构建HTML的解析树,然后使用两件事注释每个节点,该怎么办:

  1. 包含的字词总数。
  2. 包含目标字词的次数。
  3. 然后,您可以在树上搜索最大化target_count / total_count的节点。这将为您提供最小的包含元素的属性,因为树中较高的元素将包含更多单词。事实上,这样做可以为您提供目标词密度最高的节点。

    您可能会发现简单的划分并不能为您提供所需的结果。例如,如果一个节点只包含一个目标字的副本,它将具有非常高的密度,但可能与您想到的集群概念不对应。在这种情况下,我将定义一些函数,将元素中包含的单词数映射到一个大小。如果您想确保群集具有一定的大小,并且要惩罚过大的群集(例如)<body>),可能是这样的:

    def size(num_words):
       num_words = max(num_words, 40) # where 40 is the min size of a cluster
       if num_words > 1000: # This is too large, so we penalize
         num_words *= 1.5
       return num_words
    

    现在你可以做target_count / size(total_count)

    Re:scipy clustering

    此聚类适用于矢量。因此,为了使用这个软件包,你需要想出一种方法将目标单词的出现转换为向量。我无法想到一个很好的方法来做到这一点,但这并不意味着不存在这样的方式。

答案 2 :(得分:1)

群集程序包不会有太大帮助,因为不是群集分析

更多的是基于频繁模式挖掘,你可能想要研究一下。