2016-05-31 11 views
1

ich ein HTML-Dokument haben:Wie Daten nach bestimmten Wörtern analysieren

<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> 

Für Parsing verwende ich:

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 

Dieser Code ist nicht gut, weil die Reihenfolge und Anzahl der Elemente variieren kann .

Wie kann ich Daten nach bestimmten Wörtern analysieren?

UPD: In Nokogiri we can use JS selectors. Aber in meinem Fall parse nur das erste Element.

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 

Wie kann ich das beheben?

+0

Ist es immer 'KEY: VALUE' gefolgt/getrennt durch '
'? – Stefan

+0

ja. aber die Nummer
kann variieren ( – alexin

Antwort

1

darüber, wie es mit klassischen regexp Parsen:

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

Vielen Dank. Interessante Lösung. Wenn ich keine andere Lösung finde, dann benutze sie. – alexin

1

... die Reihenfolge und Anzahl der Elemente kann variieren ...

Wenn Sie nicht in der Größenordnung rechnen oder Struktur des Textes, dann müssen Sie etwas tun, um es zu zerlegen, bis es verwendbar ist.

Wenn ich darüber nachgedacht, mehr konnte ich Problem etwas schreiben effizienter, aber das ist, wo ich anfangen würde:

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" 

Es die Label und Werte in einem Hash bricht, die an diesem Punkt können Sie Einfach individuelle Werte erfassen.

1

Man könnte es mit XPath tun, oder vielleicht so etwas wie:

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

Sie wollen die anderen Lösungen zu vermeiden, mit regex Resort ist ein letztes HTML-Parsing.