Ruby - HTML 结构指纹识别

Ruby - HTML structure fingerprinting

我正在 ruby 到 'fingerprint' html 页面中寻找一种基于结构而不是内容的方法。这个想法是通过将他们的指纹与参考代码进行匹配来识别某些感兴趣的页面类型。

我找到了 this(相当旧的)工具,它似乎能很好地完成这项工作,但没有给出关于如何生成(十六进制?)代码的线索。

我曾尝试使用 Nokogiri 生成类似的东西,但使用该途径并没有太大进展...有什么建议吗?

谢谢!

所谓结构,就是指没有属性和文本的标签?

您可以尝试通过 Nokogiri(或其他地方)获得的 SAX 解析器。有两种主要类型的 XML 解析器:构建完整 XML 结构的解析器,以及在线性时间内解析文件并在其进入​​和离开元素时触发事件的 event-based 解析器。这就是 SAX 解析器的工作方式。

Nokogiri 中的示例代码是一个很好的起点:http://www.rubydoc.info/gems/nokogiri/Nokogiri/HTML/SAX/Parser

以下代码构建了遇到的标签名称数组。

# Build a list of tags.
class MyDoc < Nokogiri::XML::SAX::Document
  attr_accessor :tags

  def start_element name, attrs = []
    tags << name
  end

  def end_element name
    # NOOP
  end
end

# Create our parser
parser = Nokogiri::HTML::SAX::Parser.new(MyDoc.new)
parser.tags = []

# Send some XML to the parser
parser.parse(File.open(ARGV[0]))

假设您从这样的文档开始:

<html><head></head><body><p>This is a <strong>test</strong></p></body></html>

解析器的输出可能类似于

parser.tags # => [ 'html', 'head', 'body', 'p', 'strong' ]

编辑:修改答案以使用 HTML SAX 解析器和 HTML 纠错,而不是纯 XML 解析器(http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/SAX/Parser

我不认为这是一个简单的问题,因为有很多影响文档的因素可能会发生 解析器看到它与浏览器呈现具有的页面之后JavaScript 和 AJAX 以及后端根据不在 HTML.

中的某些标准发送不同的标记

也就是说,这是我用来生成指纹的基本思路:

require 'digest'
require 'nokogiri'

doc1 = Nokogiri::HTML.parse(<<EOT)
<html>
  <body>
    <div class='foo'><p>content</p></div>
    <div class='bar'><p>content</p></div>
  </body>
</html>
EOT

doc2 = Nokogiri::HTML.parse(<<EOT)
<html>
  <body>
    <div class='bar'><p>content</p></div>
    <div class='foo'><p>content</p></div>
  </body>
</html>
EOT

[doc1, doc2].each { |d| d.search('//text()').remove }
Digest::MD5.hexdigest(doc1.to_html) # => "3abe6e365f145452a5c99a38bfdf2339"
Digest::MD5.hexdigest(doc2.to_html) # => "25c4c66fa90c683cc2d3ce1e7e6a461b"

比较一下:

require 'digest'
require 'nokogiri'

doc1 = Nokogiri::HTML.parse(<<EOT)
<html>
  <head>
    <script>
      // a script
    </script>
  </head>
  <body>
    <div class='foo'><p>content</p></div>
    <div class='bar'><p>content</p></div>
  </body>
</html>
EOT

doc2 = Nokogiri::HTML.parse(<<EOT)
<html>
  <head>
    <script>
      // a different script
    </script>
  </head>
  <body>
    <div class='foo'><p>content</p></div>
    <div class='bar'><p>content</p></div>
  </body>
</html>
EOT

[doc1, doc2].each { |d| d.search('//text()').remove }
Digest::MD5.hexdigest(doc1.to_html) # => "13215fefd8efe06268574eaa82f4c765"
Digest::MD5.hexdigest(doc2.to_html) # => "13215fefd8efe06268574eaa82f4c765"

脚本可能不同,导致呈现不同的页面。剥离内容将剥离 JavaScript 使页面看起来相同,尽管它们可能有很大不同。

我认为准确可靠地做到这一点的唯一方法是使用类似 WATIR 的东西,它使用浏览器呈现页面,然后允许您在页面上查找文本。