2

我正在尝试使用 Nokogiri 和 Ruby 解析一些 HTML,但在做我想做的事情时遇到了一些障碍。我的示例文件如下所示:

<div id="main-body">
  <p>
    <span>First Text</span>
    <span>Second Text</span>
    <span>Third Text</span>
    <span>Fourth Text</span>
    <br>
    <span>Fifth Text</span>
    <span>Sixth Text</span>
    <span>Seventh Text</span>
    <br>
    <span>Eight Text</span>
    <span>Ninth Text</span>
    <br>
  </p>
</div

我正在尝试找到一种方法来遍历并仅选择随机中断标记之间或第一次中断之前的文本。

基本上我想让我的输出每次都不同。所以示例输出将是例如

=>First Text
=>Second Text
=>Third Text
=>Fourth Text

一次,然后,也许下一次它会在休息 2 和 3 之间得到东西

=>Eight Text
=>Ninth Text

我在想,如果我可以计算 HTML 中的中断次数,我可以使用 rand() 随机选择一个并打印出文本,直到我点击下一个,但我不能完全正确地记下来。

到目前为止,我的代码是将整个页面加载到 Nokogiri 类型并尝试从那里解析。

doc = Nokogiri::HTML(open(targeturl))
puts doc.xpath("./br").length #gives me the count of break tags in the document

从那里我实际上可以将中断分配给一个变量并一个一个地访问它们,但我不知道该去哪里,或者我什至从这里走在正确的轨道上,我觉得我只是对此感到困惑观点 :/

4

4 回答 4

1

另一个选项是 slice_before:

doc.search('p *').slice_before{|x| x.name == 'br'}.each do |slice|
  puts '*', slice.select{|x| x.name == 'span'}
end
于 2012-09-28T00:58:40.033 回答
1

count()您可以使用and来根据前面的 br 标签数量来抓取节点preceding-sibling

puts doc.xpath("//span[count(preceding-sibling::br)=0]")
#=> <span>First Text</span>
#=> <span>Second Text</span>
#=> <span>Third Text</span>
#=> <span>Fourth Text</span>

puts doc.xpath("//span[count(preceding-sibling::br)=1]")
#=> <span>Fifth Text</span>
#=> <span>Sixth Text</span>
#=> <span>Seventh Text</span>

puts doc.xpath("//span[count(preceding-sibling::br)=2]")
#=> <span>Eight Text</span>
#=> <span>Ninth Text</span>

要获得随机选择,只需随机化前兄弟的数量:

puts doc.xpath("//span[count(preceding-sibling::br)=#{rand(doc.xpath("//br").length)}]")
于 2012-09-27T15:54:17.170 回答
0

这是一个 XPath 单行表达式,它选择$k-thbr之前但不选择$k-1th之前的所有文本节点br

/*/p/br[2]/preceding-sibling::*[count(preceding-sibling::br)=1]/text()

因此,如果您k在区间中有一个随机数[1, count(/*/p/br)],那么您只需将其替换为上述 Xpath 表达式并对其进行评估。

基于 XSLT 的验证

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output  method="text"/>

 <xsl:template match="/">
     <xsl:copy-of select=
     "/*/p/br[2]/preceding-sibling::*[count(preceding-sibling::br)=1]/text()
     "/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<div id="main-body">
    <p>
        <span>First Text</span>
        <span>Second Text</span>
        <span>Third Text</span>
        <span>Fourth Text</span>
        <br/>
        <span>Fifth Text</span>
        <span>Sixth Text</span>
        <span>Seventh Text</span>
        <br/>
        <span>Eight Text</span>
        <span>Ninth Text</span>
        <br/>
    </p>
</div>

评估 XPath 表达式,并将此评估的结果(所有选定的文本节点)复制到输出

Fifth TextSixth TextSeventh Text
于 2012-09-27T17:30:34.227 回答
0

这是我的解决方案,如果你只想要 span 元素的内容(要获取整个节点,只需删除 map 操作):

require 'nokogiri'

doc = Nokogiri::XML(File.read("test.xml"))

def get_spans(doc)
    br_list = doc.css("br")
    br = br_list[rand(br_list.size)]

    span_list = []
    span = br.previous_element

    while span && span.name == "span"
         span_list << span
         span = span.previous_element
    end

    span_list.reverse.map(&:content)
end

p get_spans(doc)
于 2012-09-27T15:00:22.727 回答