2016-05-31 4 views
1

У меня есть HTML-документ:Как разобрать данные после определенных слов

<div class="info"> 
    Country: 
    <b>UK</b> 
    <br> 
    City: 
    <b>London</b> 
    <br> 
    Name: 
    <b>Jon</b> 
    <br> 
    Date: 
    <b>12.08.2014</b> 
    <br> 
</div> 

Для синтаксического анализа я использую:

name = review_meta.search('.info b')[2].text 
country = review_meta.search('.info b')[0].text 
city = review_meta.search('.info b')[1].text 
data = review_meta.search('.info b')[3].text 

Этот код не является хорошим, потому что порядок и количество элементов может изменяться ,

Как я могу анализировать данные после определенных слов?

UPD: In Nokogiri we can use JS selectors. Но в моем случае все равно проанализируйте только первый элемент.

require 'nokogiri' 
html = <<_ 
<div class="info"> 
    Country: 
    <b>UK</b> 
    <br> 
    City: 
    <b>London</b> 
    <br> 
    Name: 
    <b>Jon</b> 
    <br> 
    Date: 
    <b>12.08.2014</b> 
    <br> 
</div> 
_ 
doc = Nokogiri::HTML(html) 

country = doc.at('.info:contains("Country:") b').text 
city = doc.at('.info:contains("City:") b').text 
name = doc.at('.info:contains("Name:") b').text 
date = doc.at('.info:contains("Date:") b').text 
puts country, city, name, date # => UK UK UK Uk 

Как это исправить?

+0

Всегда ли KEY: VALUE 'следует/разделяется'
'? – Stefan

+0

есть. но число
может отличаться ( – alexin

ответ

1

Как разбором его с классическим регулярным выражением:

h = {} 
str = review_meta.search('.info')[0].text 
str.gsub(/[\n]+/, '').split('<br>').reject { |item| item == '' }.each do |item| 
    match = item.match(/([a-zA-Z]+):<b>([a-zA-Z0-9\.]+)<.b>/) 
    h[match[1].downcase.to_sym] = match[2] 
end 

p h 
=> {:country=>"UK", :city=>"London", :name=>"Jon", :date=>"12.08.2014"} 
+0

Спасибо. Интересное решение. Если я не найду другого решения, используйте его. – alexin

1

... порядок и количество элементов может варьироваться ...

Если вы не можете рассчитывать на заказ или структуры текста, тогда вам нужно что-то сделать, чтобы сломать его до тех пор, пока он не будет использоваться.

Если бы я думал об этом больше я мог бы написать что-то проблема более эффективной, но это то, где я хотел бы начать:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<div class="info"> 
    Country: 
    <b>UK</b> 
    <br> 
    City: 
    <b>London</b> 
    <br> 
    Name: 
    <b>Jon</b> 
    <br> 
    Date: 
    <b>12.08.2014</b> 
    <br> 
</div> 
EOT 

hash = doc.at('.info').text # => "\n Country:\n UK\n \n City:\n London\n \n Name:\n Jon\n \n Date:\n 12.08.2014\n \n" 
         .strip # => "Country:\n UK\n \n City:\n London\n \n Name:\n Jon\n \n Date:\n 12.08.2014" 
         .gsub(/\n +/, "\n") # => "Country:\nUK\n\nCity:\nLondon\n\nName:\nJon\n\nDate:\n12.08.2014" 
         .gsub(/:\n/, ':') # => "Country:UK\n\nCity:London\n\nName:Jon\n\nDate:12.08.2014" 
         .gsub(/\n\n/, ' ') # => "Country:UK City:London Name:Jon Date:12.08.2014" 
         .split # => ["Country:UK", "City:London", "Name:Jon", "Date:12.08.2014"] 
         .map{ |s| 
         a, b = s.split(':') 
         [a.downcase, b] 
         } # => [["country", "UK"], ["city", "London"], ["name", "Jon"], ["date", "12.08.2014"]] 
         .to_h # => {"country"=>"UK", "city"=>"London", "name"=>"Jon", "date"=>"12.08.2014"} 

hash['date'] # => "12.08.2014" 

Он ломает метки и значения в хэш, который, в этот момент вы можете легко захватывать индивидуальные значения.

1

Вы можете сделать это с помощью XPath, или может быть что-то вроде:

doc.search('.info').children.find{|x| x.text['City:']}.next.text 
#=> "London" 
doc.search('.info').children.find{|x| x.text['Name:']}.next.text 
#=> "Jon" 

Вы хотите, чтобы избежать других решений, разбора HTML с регулярным выражением является последним средством.

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

  • Нет связанных вопросов^_^