如何使用 Ruby 解析元素后的 HTML 文本
How to parse HTML text after element with Ruby
如何解析示例 HTML 并将其分组到 Ruby?
HTML 文字:
<h2>heading one</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
<h2>heading two</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<h2>heading three</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
元素没有嵌套,我想按标题对它们进行分组。当我找到一个 <h2>
时,我想提取它的文本和它后面的所有内容,直到遇到下一个 <h2>
。最后一个标题没有另一个 h2 作为分隔符。
这是示例输出:
- Heading one
"<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>"
- Heading 2
"<p>different content in here <a>test</a> <b>test</b></p>"
您可以使用 Nokogiri 非常快速地完成此操作,而无需使用正则表达式解析您的 HTML。
您将能够获取 h2
个元素,然后提取其中的内容。
一些示例位于 https://www.rubyguides.com/2012/01/parsing-html-in-ruby/
这应该有效,
第 1 组包含标题文本,
第 2 组包含 body。
包含空格 trim
/<h2\s*>\s*([\S\s]*?)\s*<\/h2\s*>\s*([\S\s]*?)(?=\s*<h2\s*>|\s*$)/
https://regex101.com/r/pgLIi0/1
可读的正则表达式
<h2 \s* >
\s*
( [\S\s]*? ) # (1) Heading
\s*
</h2 \s* >
\s*
( [\S\s]*? ) # (2) Body
(?= \s* <h2 \s* > | \s* $ )
强烈反对您尝试执行的操作,“RegEx match open tags except XHTML self-contained tags”有助于解释原因。只有在您拥有代码生成的最微不足道的情况下,您才应该使用模式。如果您不拥有生成器,那么 HTML 中的任何更改都可能破坏您的代码,通常是以无法修复的方式破坏代码,尤其是在严重停机期间的深夜,您的老板会追着您去获取它 运行立即。
使用 Nokogiri,这将使您以更稳健和推荐的方式进入球场。此示例仅收集 h2
和后续 p
节点。弄清楚如何显示它们留作练习。
require 'nokogiri'
html = <<EOT
<h2>heading 1</h2>
<p>content 1a<b>test</b></p>
<p>content 1b</p>
<h2>heading 2</h2>
<p>content 2a</p>
EOT
doc = Nokogiri::HTML.parse(html)
output = doc.search('h2').map { |h|
next_node = h.next_sibling
break unless next_node
paragraphs = []
loop do
case
when next_node.text? && next_node.blank?
when next_node.name == 'p'
paragraphs << next_node
else
break
end
next_node = next_node.next_sibling
break unless next_node
end
[h, paragraphs]
}
这导致 output
包含包含以下节点的数组:
# => [[#(Element:0x3ff4e4034be8 {
# name = "h2",
# children = [ #(Text "heading 1")]
# }),
# [#(Element:0x3ff4e4034b98 {
# name = "p",
# children = [
# #(Text "content 1a"),
# #(Element:0x3ff4e3807ccc {
# name = "b",
# children = [ #(Text "test")]
# })]
# }),
# #(Element:0x3ff4e4034ad0 {
# name = "p",
# children = [ #(Text "content 1b")]
# })]],
# [#(Element:0x3ff4e4034a6c {
# name = "h2",
# children = [ #(Text "heading 2")]
# }),
# [#(Element:0x3ff4e40349a4 {
# name = "p",
# children = [ #(Text "content 2a")]
# })]]]
该代码还对 HTML 的格式做了一些假设,但如果格式发生变化,也不会吐出垃圾。它采用如下格式:
<h2>
<p>
...
其中 h2
后面始终跟有 p
标记,直到出现其他标记,包括后续的 h2
.
本次测试:
when next_node.text? && next_node.blank?
是必要的,因为 HTML 不需要格式化,但是当它插入时 "TEXT" 节点只包含空格,这会导致我们期望 "pretty HTML" 的缩进。解析器和浏览器不关心它是否存在,除非是预格式化文本,只有人类才会关心。实际上,最好不要使用它们,因为它们会使文件膨胀并减慢文件的传输速度。但是人们就是那样挑剔。实际上,代码中的 HTML 示例看起来更像:
<h2>heading 1</h2>\n<p>content 1a<b>test</b></p>\n<p>content 1b</p>\n\n<h2>heading 2</h2>\n<p>content 2a</p>\n
并且 when
语句忽略了那些“\n
”节点。
如何解析示例 HTML 并将其分组到 Ruby?
HTML 文字:
<h2>heading one</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
<h2>heading two</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<h2>heading three</h2>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>
元素没有嵌套,我想按标题对它们进行分组。当我找到一个 <h2>
时,我想提取它的文本和它后面的所有内容,直到遇到下一个 <h2>
。最后一个标题没有另一个 h2 作为分隔符。
这是示例输出:
- Heading one
"<p>different content in here <a>test</a> <b>test</b></p>
<p>different content in here <a>test</a> <b>test</b></p>"
- Heading 2
"<p>different content in here <a>test</a> <b>test</b></p>"
您可以使用 Nokogiri 非常快速地完成此操作,而无需使用正则表达式解析您的 HTML。
您将能够获取 h2
个元素,然后提取其中的内容。
一些示例位于 https://www.rubyguides.com/2012/01/parsing-html-in-ruby/
这应该有效,
第 1 组包含标题文本,
第 2 组包含 body。
包含空格 trim
/<h2\s*>\s*([\S\s]*?)\s*<\/h2\s*>\s*([\S\s]*?)(?=\s*<h2\s*>|\s*$)/
https://regex101.com/r/pgLIi0/1
可读的正则表达式
<h2 \s* >
\s*
( [\S\s]*? ) # (1) Heading
\s*
</h2 \s* >
\s*
( [\S\s]*? ) # (2) Body
(?= \s* <h2 \s* > | \s* $ )
强烈反对您尝试执行的操作,“RegEx match open tags except XHTML self-contained tags”有助于解释原因。只有在您拥有代码生成的最微不足道的情况下,您才应该使用模式。如果您不拥有生成器,那么 HTML 中的任何更改都可能破坏您的代码,通常是以无法修复的方式破坏代码,尤其是在严重停机期间的深夜,您的老板会追着您去获取它 运行立即。
使用 Nokogiri,这将使您以更稳健和推荐的方式进入球场。此示例仅收集 h2
和后续 p
节点。弄清楚如何显示它们留作练习。
require 'nokogiri'
html = <<EOT
<h2>heading 1</h2>
<p>content 1a<b>test</b></p>
<p>content 1b</p>
<h2>heading 2</h2>
<p>content 2a</p>
EOT
doc = Nokogiri::HTML.parse(html)
output = doc.search('h2').map { |h|
next_node = h.next_sibling
break unless next_node
paragraphs = []
loop do
case
when next_node.text? && next_node.blank?
when next_node.name == 'p'
paragraphs << next_node
else
break
end
next_node = next_node.next_sibling
break unless next_node
end
[h, paragraphs]
}
这导致 output
包含包含以下节点的数组:
# => [[#(Element:0x3ff4e4034be8 {
# name = "h2",
# children = [ #(Text "heading 1")]
# }),
# [#(Element:0x3ff4e4034b98 {
# name = "p",
# children = [
# #(Text "content 1a"),
# #(Element:0x3ff4e3807ccc {
# name = "b",
# children = [ #(Text "test")]
# })]
# }),
# #(Element:0x3ff4e4034ad0 {
# name = "p",
# children = [ #(Text "content 1b")]
# })]],
# [#(Element:0x3ff4e4034a6c {
# name = "h2",
# children = [ #(Text "heading 2")]
# }),
# [#(Element:0x3ff4e40349a4 {
# name = "p",
# children = [ #(Text "content 2a")]
# })]]]
该代码还对 HTML 的格式做了一些假设,但如果格式发生变化,也不会吐出垃圾。它采用如下格式:
<h2>
<p>
...
其中 h2
后面始终跟有 p
标记,直到出现其他标记,包括后续的 h2
.
本次测试:
when next_node.text? && next_node.blank?
是必要的,因为 HTML 不需要格式化,但是当它插入时 "TEXT" 节点只包含空格,这会导致我们期望 "pretty HTML" 的缩进。解析器和浏览器不关心它是否存在,除非是预格式化文本,只有人类才会关心。实际上,最好不要使用它们,因为它们会使文件膨胀并减慢文件的传输速度。但是人们就是那样挑剔。实际上,代码中的 HTML 示例看起来更像:
<h2>heading 1</h2>\n<p>content 1a<b>test</b></p>\n<p>content 1b</p>\n\n<h2>heading 2</h2>\n<p>content 2a</p>\n
并且 when
语句忽略了那些“\n
”节点。