Разбор заголовков HTML-файлов с помощью Ruby - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть HTML-файл, который я хотел бы проанализировать в Ruby.HTML-файл очень прост и содержит только заголовки, ссылки и абзацы.Я использую нокогири для разбора.Ниже приведен пример файла HTML, с которым я имею дело:

<h1><a id="Dog_0"></a>Dog</h1>
<h2><a id="Washing_dogs_3"></a>Washing Dogs</h2>
<h3>Use soap</h3>
<h2><a id="Walking_dogs_1"></a>Walking Dogs</h2>

Мне нужно рассматривать заголовки h1 как родителя, заголовки h2 как дочерние элементы заголовка h1, а заголовки h3 как дочерние элементызаголовок h2, под которым он находится, и т.д ...

Я хочу сохранить эту информацию в массиве хэшей, так что

[ { 
   h1: "Dog",
 link: "Dog_0",  
},{
   h1: "Dog",
   h2: "Washing Dogs",
   link: "Dog_0#Washing_dogs_3"
},{
   h1: "Dog",
   h2: "Washing Dogs",
   h3: "Use Soap",
   link: "Dog_0#Washing_dogs_3"
},{
   h1: "Dog",
   h2: "Walking Dogs"
   link: "Dog_0#Walking_dogs_1"
}]

Поскольку ни один из узлов не является вложенным, я не наденуНе думаю, что я могу использовать какие-либо полезные методы для поиска детей.На данный момент у меня есть следующее:

array_of_records = []; #Store the records in an array
desired_headings = ['h1','h2','h3','h4','p'] # headings used to split html 
into records

Dir.glob('*.html') { |html_file|


  nokogiri_object = File.open(html_file) { |f| Nokogiri::HTML(f, nil, 'UTF- 
8') }

  nokogiri_object.traverse { |node|
   next unless desired_headings.include?(node.name)
   record = {}
   record[node.name.to_sym] = node.text.gsub(/[\r\n]/,'').split.join(" ")
   link = node.css('a')[0]

   record[:link] = link['id'] if !link.nil?

   array_of_records << record
  }

Этот код позволяет захватить заголовок, который я анализирую, и сохраняет его содержимое в хэше как

 {heading: "content"} 

, но не захватывает родительскийкак информация, которую мне нужно захватить.

Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Итак, я нашел решение, которое в основном работает, за исключением того, что оно не хранит мои «записи» в моем массиве записей, как я хочу. Мое решение

require "rubygems"
require "nokogiri"
require "json"   

array_of_records = [] #Store the records in an array
desired_headings = ['h1','h2','h3','h4','p'] # headings used to split html into 
records

Dir.glob('./source/*.html') { |html_file|

  latest_headings = {}; # hash to store latest data from headings

  nokogiri_object = File.open(html_file) { |f| Nokogiri::HTML(f, nil, 'UTF-8') }
  nokogiri_object.traverse { |node|

    next unless desired_headings.include?(node.name)

    case node.name
    when ("h1".."h4")

      @record = {}
      latest_headings[node.name] = node.text
      latest_headings.each { |key,value|
        @record[key] = value if key <= node.name
      }
      link = node.css('a')[0]
      link = link['id'] if !link.nil?
      @record['link'] = link if !link.nil?
    when "p"
      @record['content'] = node.text
    end

    array_of_records << @record
    puts @record

  } #end loop through nodes
 puts array_of_records    

} #end loop through files

Я ожидаю, что puts @record напечатает то же самое, что напечатает puts array_of_records, но я обнаружил, что array_of_records не содержит того, что puts @record prints. Какие-либо предложения?

0 голосов
/ 12 сентября 2018

traverse хорошая идея.Вы хотите отслеживать последние h1, h2, h3 и т.д: ...

@state = {}
records = []
nokogiri_object.traverse { |node|
  next unless desired_headings.include?(node.name)
  @state[node.name] = node.text
  case node.name
    when 'h1'
      records << {
        h1: @state['h1']
      }
    when 'h2'
      records << {
        h1: @state['h1'],
        h2: @state['h2'],
      }

  end
}
...