如何一次访问一个<p>标记

时间:2016-11-28 21:10:46

标签: ruby-on-rails ruby nokogiri

我有以下HTML:

<div id="test_id">
    <p>Some words.</p>
    <p>Some more words.</p>
    <p>Even more words.</p>
</div>

如果我使用以下方式解析HTML:

doc = Nokogiri::HTML(open("http://my_url"))

并运行

doc.css('#test_id').text
在控制台中我得到:

=> "Some words.\nSome more words.\nEven more words"

如何仅获取第一个<p>元素?

我想我用.children

来解决这个问题
doc.css('#test_id').children[0].text

这是正确的方法吗?

2 个答案:

答案 0 :(得分:2)

问题是你没有在正确类型的对象上使用text

如果您正在查看NodeSet text文档中的Node

  

获取所有包含的Node对象的内部文本

如果你正在查看How to avoid joining all text from Nodes when scraping AKA元素,它会说:

  

返回此节点的内容

区别在于:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<div id="test_id">
    <p>Some words.</p>
    <p>Some more words.</p>
    <p>Even more words.</p>
</div>
EOT

doc.search('p').class  # => Nokogiri::XML::NodeSet
doc.search('p').text  # => "Some words.Some more words.Even more words."

doc.at('p').class  # => Nokogiri::XML::Element
doc.at('p').text  # => "Some words."

atsearch(...).first类似。

通常,如果我们想要使用NodeSet的文本:

doc.search('p').map(&:text)  # => ["Some words.", "Some more words.", "Even more words."]

可以轻松选择特定节点的文本。

另请参阅“enter image description here”。

  

doc.css('#test_id').children[0].text

嗯,是的,你可以这样做,但children不会做同样的事情:

doc.search('#test_id').children
# => [#<Nokogiri::XML::Text:0x3fc31580ca24 "\n    ">, #<Nokogiri::XML::Element:0x3fc315103714 name="p" children=[#<Nokogiri::XML::Text:0x3fc31580d5a0 "Some words.">]>, #<Nokogiri::XML::Text:0x3fc315107f44 "\n    ">, #<Nokogiri::XML::Element:0x3fc3151036ec name="p" children=[#<Nokogiri::XML::Text:0x3fc315107cc4 "Some more words.">]>, #<Nokogiri::XML::Text:0x3fc315107b20 "\n    ">, #<Nokogiri::XML::Element:0x3fc3151036c4 name="p" children=[#<Nokogiri::XML::Text:0x3fc3151078a0 "Even more words.">]>, #<Nokogiri::XML::Text:0x3fc3151076fc "\n">]
doc.search('#test_id').children[0] # => #<Nokogiri::XML::Text:0x3fc31580ca24 "\n    ">
doc.search('#test_id').children[1] # => #<Nokogiri::XML::Element:0x3fc315103714 name="p" children=[#<Nokogiri::XML::Text:0x3fc31580d5a0 "Some words.">]>

doc.search('#test_id p')
# => [#<Nokogiri::XML::Element:0x3fc315103714 name="p" children=[#<Nokogiri::XML::Text:0x3fc31580d5a0 "Some words.">]>, #<Nokogiri::XML::Element:0x3fc3151036ec name="p" children=[#<Nokogiri::XML::Text:0x3fc315107cc4 "Some more words.">]>, #<Nokogiri::XML::Element:0x3fc3151036c4 name="p" children=[#<Nokogiri::XML::Text:0x3fc3151078a0 "Even more words.">]>]
doc.search('#test_id p')[0] # => #<Nokogiri::XML::Element:0x3fc315103714 name="p" children=[#<Nokogiri::XML::Text:0x3fc31580d5a0 "Some words.">]>
doc.search('#test_id p')[1] # => #<Nokogiri::XML::Element:0x3fc3151036ec name="p" children=[#<Nokogiri::XML::Text:0x3fc315107cc4 "Some more words.">]>

注意children如何返回用于格式化HTML的标记之间的文本节点。您必须知道children会在所选标记下方的HTML中返回所有。这有时很有用,但对于一般的文本检索,它可能不是你想要的。

相反,使用更具选择性的'#test_id p'选择器并迭代返回的NodeSet,您将避免格式化文本节点,并且在将Node或索引用于NodeSet时不必考虑它们。 / p>

答案 1 :(得分:0)

您也可以试试这个。

$("p:first-child").text();

这将为您提供任何父元素的所有第一个子元素。所以对于你的例子它应该工作