【问题标题】:Identifying if 2 HTML pages are similar识别 2 个 HTML 页面是否相似
【发布时间】:2008-09-20 10:58:21
【问题描述】:

我正在尝试确定基本案例和提供的案例之间的差异。正在寻找一个库来告诉我相似度的百分比或类似的东西。

例如:

我有 10 个不同的 HTML 页面。 * 都是 404 响应,只有一个 2 行随机代码(例如时间或当天的报价)。

现在,当我提供一个新的 404 页面时,我希望返回类似“%80”的结果,但是如果我提供另一个完全不同或相同网站但内容完全不同的页面,我应该得到一些“%20 相似”的结果。

基本上我想要做的是,当我收到新回复时,我想确定新回复是否与我之前提供的这 10 页相似。

我正在尝试在 .NET 中解决这个问题,库或算法推荐会很棒。

【问题讨论】:

    标签: .net diff similarity fuzzy


    【解决方案1】:

    您可以使用复制/粘贴检测器 (cpd),而不是使用差异工具。然后,您可以配置您希望文件的相似程度的阈值。

    顺便说一句,我过去曾用这些来追踪学校里的作弊者。

    山姆

    【讨论】:

      【解决方案2】:

      如果您想使用基于字符串的解决方案,您可以使用 k-gram 进行尝试(您计算两个文件的所有长度为 k 的连续字符的字符串,然后对结果集执行 Jaccard 距离)。这是在 DB 世界中执行近似查询的标准方式。

      如果您对嵌入到 html 文件中的分层信息更感兴趣(例如,您正在谈论一个不可变的部分),您可以将其转换为 xhtml(对于 java,您有 http://htmlcleaner.sourceforge.net/,我不喜欢 .net 但我认为该环境也有几种替代方案),将文件生成为有序标记树,您可以使用 pq-grams(http://www.inf.unibz.it/~augsten/publ/tods10/ 用于纸张和 java 代码)来评估结构相似性(pq-grams 是字符串 k-gram)。

      此时,如果您愿意,您可以对包含文本的叶子执行基于哈希的比较,或者对这个叶子使用 k-gram,对其余部分使用基于结构 pq-gram 的相似性。

      【讨论】:

        【解决方案3】:

        一种快速而肮脏的方法是计算标记的 Levenshtein 距离。

        http://en.wikipedia.org/wiki/Levenstein_distance

        【讨论】:

          【解决方案4】:

          对于您的任务,运行命令行 diff 实用程序并分析结果就足够了。

          或者,您需要实现 LCS 算法,但对我来说这将是一个矫枉过正。

          【讨论】:

            【解决方案5】:

            对于您的任务,这足以 运行命令行 diff 实用程序和 分析结果。

            这真的不是一次性的工作,我需要一个集成到应用程序中的解决方案。

            而且 diff 在这里有它自己的问题,因为我不能告诉 diff 处理 5 个页面并忽略那些不断变化的位。

            这些部分可以很大,2kb 的标准文本可以不断变化。而且我认为从差异的角度来看这是一个很大的变化,但从我的角度来看,这只是一个部分的变化(已知在所有其他 9 个文件中都会发生变化,因此应该完全忽略)。

            也许差异库可以做到这一点,但我不知道这样的库。

            【讨论】:

              【解决方案6】:

              我会使用的基本算法:

              解析新旧两边页面的文本内容。当您解析时,请跟踪已处理的字节数,以便稍后使用以确定有多少 % 已更改。现在你在每一边都有完整的故事,建立相同的锚点。对于你所拥有的每一个相同的锚点,试着向前和向后扩展它。将您的相同锚点之间的任何差距确定为差异。遍历您已识别的每个差异间隙并总结它们的字节数。通过使用总数量差异字节数和故事的总字节(您之前计算的那个)来计算您的差异百分比。

              【讨论】:

                【解决方案7】:

                您可以使用 jqgram,一种 PQ-Gram 树编辑距离近似的实现来专门解决此问题,但如果您不想移植到 C#,则需要运行 Node.js。不过,端口应该很容易......算法并不是那么复杂。简约之美。

                https://github.com/hoonto/jqgram

                在这个例子中是一个 DOM 与 Cheerio 的例子,它展示了如何处理孩子和标签以生成近似的树编辑距离。结果,它为您提供了一个介于 0 和 1 之间的数字,这就是您的百分比相等。但请注意,零值并不一定表示相同的树,它仅表示它们非常相似。您也可以轻松地进行 DOM 与 DOM 比较或 Cheerio 与 Cheerio - 或使用 Cheerio 使用的 HTML 解析,而不用担心使用整个库(开箱即用的 Cheerio 是一个相当快的服务器端 jQuery 和类似 DOM实施)。

                很明显,这个解决方案是特定于 Node.js 和浏览器 javascript,但我认为这些挑战可能比移植到 C#/.NET 更容易。

                // This could probably be optimized significantly, but is a real-world
                // example of how to use tree edit distance in the browser.
                
                // For cheerio, you'll have to browserify, 
                // which requires some fiddling around
                // due to cheerio's dynamically generated 
                // require's (good grief) that browserify 
                // does not see due to the static nature 
                // of its code analysis (dynamic off-line
                // analysis is hard, but doable).
                //
                // Ultimately, the goal is to end up with 
                // something like this in the browser:
                
                var cheerio = require('./lib/cheerio'); 
                
                // The easy part, jqgram:
                var jq = require("../jqgram").jqgram;
                
                // Make a cheerio DOM:
                var html = '<body><div id="a"><div class="c d"><span>Irrelevent text</span></div></div></body>';
                
                var cheeriodom = cheerio.load(html, {
                    ignoreWhitespace: false,
                    lowerCaseTags: true
                });
                
                // For ease, lets assume you have jQuery laoded:
                var realdom = $('body');
                
                // The lfn and cfn functions allow you to specify
                // how labels and children should be defined:
                jq.distance({
                    root: cheeriodom,
                    lfn: function(node){ 
                        // We don't have to lowercase this because we already
                        // asked cheerio to do that for us above (lowerCaseTags).
                        return node.name; 
                    },
                    cfn: function(node){ 
                        // Cheerio maintains attributes in the attribs array:
                        // We're going to put id's and classes in as children 
                        // of nodes in our cheerio tree
                        var retarr = []; 
                        if(!! node.attribs && !! node.attribs.class){
                            retarr = retarr.concat(node.attribs.class.split(' '));
                        }
                        if(!! node.attribs && !! node.attribs.id){
                            retarr.push(node.attribs.id);
                        }
                        retarr = retarr.concat(node.children);
                        return  retarr;
                    }
                },{
                    root: realdom,
                    lfn: function(node){ 
                        return node.nodeName.toLowerCase(); 
                    },
                    cfn: function(node){ 
                        var retarr = [];
                        if(!! node.attributes && !! node.attributes.class && !! node.attributes.class.nodeValue){
                            retarr = retarr.concat(node.attributes.class.nodeValue.split(' '));
                        }
                        if(!! node.attributes && !! node.attributes.id && !! node.attributes.id.nodeValue) {
                            retarr.push(node.attributes.id.nodeValue);
                        }
                        for(var i=0; i<node.children.length; ++i){
                            retarr.push(node.children[i]);
                        }
                        return retarr;
                    }
                },{ p:2, q:3, depth:10 },
                function(result) {
                    console.log(result.distance);
                });
                

                【讨论】:

                  猜你喜欢
                  • 2018-04-30
                  • 2017-11-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-03-21
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-11-04
                  • 2022-12-18
                  相关资源
                  最近更新 更多