【问题标题】:Parsing with Xpath使用 Xpath 解析
【发布时间】:2014-07-25 08:42:49
【问题描述】:

考虑以下 HTML:

<div class='data'>
  <div class='user_name'>Lankesh</div>
  <div class='user_details'>
    <div class='country'>Srilanka</div>
    <div class='age'>9</div>
  </div>
  <div class='user_name'>Bob</div>
  <div class='user_details'>
    <div class='country'>US</div>
    <div class='age'>54</div>
  </div>
  <div class='user_name'>Deiter</div>
  <div class='user_details'>
    <div class='country'>Germany</div>
    <div class='age'>34</div>
  </div>
  <div class='user_name'>Yakob</div>
  <div class='user_details'>
    <div class='country'>Syria</div>
    <div class='age'>90</div>
  </div>
  <div class='user_name'>Qureshi</div>
  <div class='user_details'>
    <div class='country'>Afgan</div>
    <div class='age'>56</div>
  </div>
  <div class='user_name'>Smith George</div>
  <div class='user_details'>
    <div class='country'>India</div>
    <div class='age'>23</div>
  </div>
</div>

还有以下 Ruby 代码:

require 'nokogiri'

sample_html = File.open("r.htm", "r").read

n = Nokogiri::HTML::parse sample_html

xpaths = {}

xpaths[:name] = "//div[@class = 'user_name']/text()"
xpaths[:country] = "//div[@class = 'country']/text()"
xpaths[:age] = "//div[@class = 'age']/text()"

full_path = xpaths.values.join(" | ")

n.xpath(full_path).each do |i|
  puts i
end

这可以提取数据,但我如何分块(姓名、年龄和国家),以便我可以更轻松地将解析后的数据提取到结构中。

  • 由于名称在 user_details 块之外,我无法编写如下查询://div[@class = 'user_details'] 并提取每个属性。
  • 我知道我可以将数组分成 3 个组;但我正在寻找基于 xpath 的解决方案,因为我的实际需要有不同数量的子属性。
  • 很傻,但是:无论如何,在解析期间以某种方式将字符注入到提取的文本中?

有什么想法吗?

【问题讨论】:

    标签: html ruby xpath nokogiri


    【解决方案1】:

    首先让我说最好调整 HTML 以将每个用户块包装在其自己的包含 div 中:

    <div class='user'>
        <div class='name'>John</div>
        <div class='details'>
            <div class='country'>US</div>
            ...
        </div>
    </div>
    

    然后您可以简单地使用"//div[@class = 'user']" 分别查询每个用户块。不过,您可能无法控制 HTML。

    鉴于目前的情况,我建议简单地获取 user_name div 以及 user_details div 并将它们压缩在一起。然后,您可以根据子 div (.xpath("div")) 从用户详细信息创建一个哈希,这将适用于任意数量的 user_details,并将其类属性用作哈希键,将其文本用作值。请注意,此实现仅适用于单级 user_details。当然,如果不是所有 user_details 子 div 都具有类属性,则必须进行调整。但从您的示例输入来看,它们确实如此。

    require 'pp'
    require 'nokogiri'
    
    sample_html = File.open("r.htm", "r").read
    
    n = Nokogiri::HTML::parse sample_html
    
    user_names = n.xpath("//div[@class = 'user_name']")
    user_details = n.xpath("//div[@class = 'user_details']")
    
    users = user_names.zip(user_details).map do |name, details|
      {
        name: name.text,
        details: Hash[details.xpath("div").map { |d| [d['class'].to_sym, d.text] }]
      }
    end
    
    pp users
    
    # [{:name=>"Lankesh", :details=>{:country=>"Srilanka", :age=>"9"}},
    #  {:name=>"Bob", :details=>{:country=>"US", :age=>"54"}},
    #  {:name=>"Deiter", :details=>{:country=>"Germany", :age=>"34"}},
    #  {:name=>"Yakob", :details=>{:country=>"Syria", :age=>"90"}},
    #  {:name=>"Qureshi", :details=>{:country=>"Afgan", :age=>"56"}},
    #  {:name=>"Smith George", :details=>{:country=>"India", :age=>"23"}}]
    

    【讨论】:

    • 是的,你猜对了,我无法控制 HTML。我理解拉链。但是有没有办法使用 XPath 完成这个(也许我正在成像关于 XPath 的东西)
    • 我不这么认为,主要是因为 XPath 返回结果的平面列表,并且由于您的源没有分组,结果也不会。您是否有任何理由希望它仅在 XPath 中完成?您说这是因为 user_details 具有不同数量的属性,但是我的解决方案在将其解析为数据结构时解决了该问题,这正是您想要的:)?
    • 你是对的,但不知何故被它的实际解析方式弄糊涂了,这就是我进一步寻找的原因。你的回答肯定是对的。但是,只需寻找我发布的另一个问题;这就是我真正想要帮助的,试图理解 XPath。
    猜你喜欢
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    相关资源
    最近更新 更多