28

我用 Ruby 编写了一个网络爬虫,我正在使用Nokogiri::HTML它来解析页面。我需要将页面打印出来,在 IRB 中搞乱时我注意到了一种pretty_print方法。但是它需要一个参数,我无法弄清楚它想要什么。

我的爬虫正在缓存网页的 HTML 并将其写入本地计算机上的文件。我想“漂亮地打印”HTML,这样当我这样做时它看起来不错并且格式正确。

4

8 回答 8

81

@mislav 的回答有些错误。如果您满足以下条件,Nokogiri 确实支持漂亮的打印:

  • 将文档解析为 XML
  • 指示 Nokogiri 在解析期间忽略仅空白节点(“空白”)
  • 使用to_xhtmlto_xml指定漂亮的打印参数

在行动:

html = '<section>
<h1>Main Section 1</h1><p>Intro</p>
<section>
<h2>Subhead 1.1</h2><p>Meat</p><p>MOAR MEAT</p>
</section><section>
<h2>Subhead 1.2</h2><p>Meat</p>
</section></section>'

require 'nokogiri'
doc = Nokogiri::XML(html,&:noblanks)
puts doc
#=> <section>
#=>   <h1>Main Section 1</h1>
#=>   <p>Intro</p>
#=>   <section>
#=>     <h2>Subhead 1.1</h2>
#=>     <p>Meat</p>
#=>     <p>MOAR MEAT</p>
#=>   </section>
#=>   <section>
#=>     <h2>Subhead 1.2</h2>
#=>     <p>Meat</p>
#=>   </section>
#=> </section>

puts doc.to_xhtml( indent:3, indent_text:"." )
#=> <section>
#=> ...<h1>Main Section 1</h1>
#=> ...<p>Intro</p>
#=> ...<section>
#=> ......<h2>Subhead 1.1</h2>
#=> ......<p>Meat</p>
#=> ......<p>MOAR MEAT</p>
#=> ...</section>
#=> ...<section>
#=> ......<h2>Subhead 1.2</h2>
#=> ......<p>Meat</p>
#=> ...</section>
#=> </section>
于 2011-10-20T16:17:57.140 回答
19

通过 HTML 页面的“漂亮打印”,我认为您的意思是您想用适当的缩进重新格式化 HTML 结构。Nokogiri 不支持这个;该pretty_print方法适用于“pp”库,输出仅对调试有用。

有几个项目对 HTML 的理解足够好,能够在不破坏实际重要的空白的情况下重新格式化它(著名的是HTML Tidy),但通过谷歌搜索,我发现这篇文章的标题是“使用 Nokogiri 和 XSLT 漂亮地打印 XHTML” .

归结为:

xsl = Nokogiri::XSLT(File.open("pretty_print.xsl"))
html = Nokogiri(File.open("source.html"))
puts xsl.apply_to(html).to_s

当然,它要求您将链接的 XSL 文件下载到您的文件系统。我已经在我的机器上很快地尝试了它,它就像一个魅力。

于 2009-12-14T15:50:04.973 回答
9

这对我有用:

 pretty_html = Nokogiri::HTML(html).to_xhtml(indent: 3) 

我尝试了上面的 REXML 版本,但它损坏了我的一些文档。而且我讨厌将 xslt 带入一个新项目。两人都觉得过时了。:)

于 2014-11-14T01:36:51.583 回答
4

您可以尝试 REXML:

require "rexml/document"

doc = REXML::Document.new(xml)
doc.write($stdout, 2)
于 2010-11-20T20:55:15.550 回答
2

print我的解决方案是在实际Nokogiri对象上添加一个方法。运行下面代码片段中的代码后,您应该能够编写node.print,并且它会漂亮地打印内容。不需要 xslt :-)

Nokogiri::XML::Node.class_eval do
  # Print every Node by default (will be overridden by CharacterData)
  define_method :should_print? do
    true
  end

  # Duplicate this node, replace the contents of the duplicated node with a
  # newline. With this content substitution, the #to_s method conveniently
  # returns a string with the opening tag (e.g. `<a href="foo">`) on the first
  # line and the closing tag on the second (e.g. `</a>`, provided that the
  # current node is not a self-closing tag).
  #
  # Now, print the open tag preceded by the correct amount of indentation, then
  # recursively print this node's children (with extra indentation), and then
  # print the close tag (if there is a closing tag)
  define_method :print do |indent=0|
    duplicate = self.dup
    duplicate.content = "\n"
    open_tag, close_tag = duplicate.to_s.split("\n")

    puts (" " * indent) + open_tag
    self.children.select(&:should_print?).each { |child| child.print(indent + 2) }
    puts (" " * indent) + close_tag if close_tag
  end
end

Nokogiri::XML::CharacterData.class_eval do
  # Only print CharacterData if there's non-whitespace content
  define_method :should_print? do
    content =~ /\S+/
  end

  # Replace all consecutive whitespace characters by a single space; precede the
  # outut by a certain amount of indentation; print this text.
  define_method :print do |indent=0|
    puts (" " * indent) + to_s.strip.sub(/\s+/, ' ')
  end
end
于 2015-08-29T23:46:34.073 回答
0

我知道我回答这个问题已经很晚了,但我仍然会留下答案。我尝试了上述所有步骤,并且在一定程度上确实有效。

Nokogiri确实格式化HTML但不关心结束或开始标签,因此漂亮的格式不在图片中。

我发现了一个叫做htmlbeautifier的 gem ,它就像一个魅力。我希望仍在寻找答案的其他人会发现这很有价值。

于 2020-09-13T15:40:12.817 回答
0

更简单,效果很好

puts Nokogiri::HTML(File.read('terms.fr.html')).to_xhtml
于 2021-09-18T11:59:39.097 回答
-6

你为什么不试试这个pp方法?

require 'pp'
pp some_var
于 2009-12-14T04:23:40.483 回答