Ruby - HTML结构指纹识别

时间:2017-01-26 13:22:31

标签: html ruby nokogiri

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

我找到了this(相当古老)的工具,似乎做得很好,但没有提供关于如何生成(十六进制?)代码的线索。

我尝试使用Nokogiri生成类似的东西,但使用该途径取得的进展并不多......有什么建议吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

根据结构,您只是指没有属性且没有文本的标签?

您可以尝试通过Nokogiri(或其他地方)提供的SAX解析器。有两种主要类型的XML解析器:构建完整XML结构的解析器,以及基于事件的解析器,它以线性时间解析文件,并在事件进入和离开元素时触发事件。这就是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纠错的HTML SAX解析器的答案而不是纯XML解析器(http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/SAX/Parser

答案 1 :(得分:1)

我不认为这是一个简单的问题,因为在解析器看到之后可能会发生影响的文件与渲染具有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的东西,它使用浏览器渲染页面然后允许您在页面上查找文本。