我有以下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
这是正确的方法吗?
答案 0 :(得分:2)
问题是你没有在正确类型的对象上使用text
。
获取所有包含的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."
at
与search(...).first
类似。
通常,如果我们想要使用NodeSet的文本:
doc.search('p').map(&:text) # => ["Some words.", "Some more words.", "Even more words."]
可以轻松选择特定节点的文本。
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();
这将为您提供任何父元素的所有第一个子元素。所以对于你的例子它应该工作