【问题标题】:How to parse HTML file headings with Ruby如何使用 Ruby 解析 HTML 文件标题
【发布时间】:2019-02-16 15:22:21
【问题描述】:

我有一个要在 Ruby 中解析的 HTML 文件。 HTML 文件非常简单,只包含标题、链接和段落。我正在使用 Nokogiri 进行解析。

我正在处理的一个 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"} 

但没有捕获我需要捕获的类似父级的信息。

【问题讨论】:

    标签: html ruby parsing nokogiri


    【解决方案1】:

    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
    }
    

    【讨论】:

    • 嗨!您认为您可以查看我发布的答案并就如何改进它/解决我遇到的问题给我建议吗?谢谢!
    【解决方案2】:

    所以,我想出了一个最有效的解决方案,只是它没有按照我的意愿将我的“记录”存储在我的记录数组中。我的解决方案是

    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 的内容。有什么建议?

    【讨论】:

    • 请不要在“最有效”的答案中添加代码。答案必须是有效的解决方案。此外,不要提示其他评论或信息,例如“有什么建议吗?”在一个答案中。答案仅用于此目的,而 cmets 用于评论和要求提问者提供更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 2013-04-02
    • 2014-02-07
    • 2014-07-05
    • 2012-05-26
    • 2014-10-09
    • 2016-09-15
    相关资源
    最近更新 更多