2015-12-11 4 views
0

Я использую Nokogiri (v 1.6.6) в Ruby (v 2.2), чтобы очистить данные из файлов HTML. Целевые данные находятся в <p> элементах, как показано ниже. Я могу чавкать все текстовое содержимое с:Извлечь текст между узлами с помощью Nokogiri в скрипте Ruby

require 'nokogiri' 

doc = Nokogiri::HTML(DATA.read) 

doc.css("div.listing > p").each do |p| 
    puts p.text 
end 

__END__ 
<div class="listing"> 
    <p><span>1</span> Details1 <span>info1</span></p> 
    <p><span>2</span> Details2 <span>info2</span></p> 
    <p><span>3</span> Details3 <span>info3</span></p> 
</div> 

который возвращает:

1 Details1 info1 
2 Details2 info2 
3 Details3 info3 

В то время как я могу легко разобрать текст внутри тегов <span>, я не понял, как получите текст «Подробности #» между ними. Это достаточно легко сделать с помощью регулярного выражения, но я хотел бы посмотреть, есть ли способ сделать это прямо из Nokigiri. Цель состоит в том, чтобы вернуть:

Details1 
Details2 
Details3 

Возможно ли использование встроенной функциональности Nokogiri?

ответ

0

Вот что я закончил с:

doc.css("div.listing > p").each do |p| 
    puts p.at_xpath('./text()').text.strip 
end 

Согласно «Get text directly inside a tag in Nokogiri», метод text() будет

получить все прямые дети с текстом, но не любые дальнейшие суб-детей

Это поведение, которое я вижу, и оно дало ожидаемые результаты.

1

Я думаю, что если вы ныряете немного в «Getting Mugged by Nokogiri» вы найдете ответ, но я дам свой подход к вашему вопросу:

irb(main):061:0> doc = Nokogiri::HTML("<div class='listing'> <p><span>1</span> Details1 <span>info1</span></p> <p><span>2</span> Details2 <span>info2</span></p> <p><span>3</span> Details3 <span>info3</span></p> </div>") 

Это даст вам объект Nokogiri называется doc:

=> #<Nokogiri::HTML::Document:0x2ab03653f26c name="document" children=[#<Nokogiri::XML::DTD:0x2ab03653ef4c name="html">, #<Nokogiri::XML::Element:0x2ab03653ece0 name="html" children=[#<Nokogiri::XML::Element:0x2ab03653eb00 name="body" children=[#<Nokogiri::XML::Element:0x2ab03653e920 name="div" attributes=[#<Nokogiri::XML::Attr:0x2ab03653e8bc name="class" value="listing">] children=[#<Nokogiri::XML::Text:0x2ab03653e484 " ">, #<Nokogiri::XML::Element:0x2ab03653e3d0 name="p" children=[#<Nokogiri::XML::Element:0x2ab03653e1f0 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653e010 "1">]>, #<Nokogiri::XML::Text:0x2ab03653de58 " Details1 ">, #<Nokogiri::XML::Element:0x2ab03653dda4 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653db9c "info1">]>]>, #<Nokogiri::XML::Text:0x2ab03653d8f4 " ">, #<Nokogiri::XML::Element:0x2ab03653d840 name="p" children=[#<Nokogiri::XML::Element:0x2ab03653d660 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653d480 "2">]>, #<Nokogiri::XML::Text:0x2ab03653d2dc " Details2 ">, #<Nokogiri::XML::Element:0x2ab03653d228 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653d048 "info2">]>]>, #<Nokogiri::XML::Text:0x2ab03653cdb4 " ">, #<Nokogiri::XML::Element:0x2ab03653cd00 name="p" children=[#<Nokogiri::XML::Element:0x2ab03653cb20 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653c940 "3">]>, #<Nokogiri::XML::Text:0x2ab03653c79c " Details3 ">, #<Nokogiri::XML::Element:0x2ab03653c6e8 name="span" children=[#<Nokogiri::XML::Text:0x2ab03653c508 "info3">]>]>, #<Nokogiri::XML::Text:0x2ab03653c274 " ">]>]>]>]> 

И тогда вы будете в состоянии перебрать объекта:

«Метод трассировки рекурсивно проходит через все дочерние узлы. Мы проверяем, является ли узел является текстовым узлом, и если его родительский узел является пунктом.»

irb(main):068:0> doc.at_css("body").traverse do |node| 
irb(main):069:1* if node.text? && (node.parent.name == "p") 
irb(main):070:2>  puts node.content 
irb(main):071:2> end 
irb(main):072:1> end 
Details1 
Details2 
Details3 
=> nil 
irb(main):073:0> 

Я должен сказать, что я не знал о traverse так что ваш вопрос был очень полезным для меня, как я используйте Nokogiri daily. Надеюсь, вы найдете этот ответ полезным.

Смежные вопросы