【问题标题】:CSS selectors and conditionals in a ruby scriptruby 脚本中的 CSS 选择器和条件
【发布时间】:2012-05-26 12:50:40
【问题描述】:

我正在尝试使用 Nokogiri 和 CSS 选择器在 Ruby 中编写一个脚本来解析 Wikipedia 文章。不过,我对脚本中的条件有点困惑。这是我目前所拥有的(page 是使用 Nokogiri 下载的 html):

page.css('h3').each do |node|
  puts node.text
end

page.css('li').each do |node|   
  if /\d|\D/.match(node)
    puts node.text.scan(/[\d]+\D*/).first
  end
end

page.css('td b').each do |node|
  puts node.text
end

这一切都很好。但是,我真正想要的是这样的:

page.css('h3, li, td b').each do |node|
  # if it's an h3 node, do one thing
  # if it's a li node, do another thing
  # else if it's a 'td b' node, do another thing
end

这将允许按顺序解析页面,而不是分别遍历正文三次。但是,我不确定如何在我的脚本中编写这些条件。

编辑: 所以现在我的脚本是

page.css('h3, li, td b').each do |node|
        case node.name
        when 'h3', 'b'
            puts node.text
        when 'li'
            if /\d|\D/.match(node)
                puts node.text.scan(/[\d]+\D*/).first
            end
        else
            next
    end
end

但是,它并没有改变行为。它以与之前相同的顺序处理它们(所有 'h3' 元素,然后是所有 'li' 元素,然后是所有 'b' 元素)。

编辑 2:

好的,我终于让它工作了。这是我的最后一组条件:

page.traverse do |node|
    case
            when 'h3' == node.name 
            puts node.text
        when 'li' == node.name 
            puts node.text.scan(/[\d]+\D*/).first if /\d|\D/.match(node)
        when 'b' == node.name
            puts node.text if (node.parent.name == 'p' or node.parent.name == 'td')
    end
end

谢谢!

【问题讨论】:

  • 正如下面的 Mark 所指出的,您现在拥有的绝对没有问题,将它们分开总比组合好。

标签: ruby css-selectors nokogiri


【解决方案1】:

您可能正在寻找遍历:

page.traverse do |node|
  case
    when ['h3', 'li'].include?(node.name) then puts node.text
    when 'b' == node.name && 'td' == node.parent.name then puts node.text[/\d+\D*/]
  end
end

【讨论】:

  • 问题:我得到了我想要的一切,但我的输出中也出现了随机的空白行。您能想到任何原因吗?
  • 嗯,你可能想把它改成: puts $1 if node.text[/\d+\D*/]
  • 不走运。 1 美元应该做什么?
  • 这只是编写正则表达式行的一种更短的方式。试试 node.text.strip / $1.strip 你要么有一个额外的换行符,要么是一个空文本。
【解决方案2】:

使用 Nokogiri,即使在您的第一个场景中,页面也不会被解析三次。 Nokogiri 解析页面一次,创建内存中的 DOM,然后使用 DOM 查找所需的节点。执行多个 CSS 或 XPath 查找并不是低效的。

不过,如果你还想一次抓取所有节点,你可以这样做:

page.css('h3, li, td b').each do |node|
  case node.name
  when 'h3'
    do_something
  when 'li'
    do_something_else
  when 'b'
    do_another_thing
end

请注意,如果您需要区分td bp b,则此技术将不起作用。我建议单独查找。

【讨论】:

  • 查看我的编辑。没有太多运气尝试了你的建议(我不认为)。
  • 啊,根据您的编辑,我看到您想确保它们是按文档顺序处理的。我的假设是,如果重新解析,您会担心性能。 @pguardiario 有你想要的答案。
猜你喜欢
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
相关资源
最近更新 更多