【问题标题】:Nokogiri grab only visible inner_textNokogiri 只抓取可见的 inner_text
【发布时间】:2012-03-27 05:02:37
【问题描述】:

有没有更好的方法来使用 Nokogiri 提取网页上的可见文本?目前我使用inner_text 方法,但是该方法将大量JavaScript 视为可见文本。我想捕捉的唯一文本是屏幕上的可见文本。

例如,在 IRB 中,如果我在 Ruby 1.9.2-p290 中执行以下操作:

require 'nokogiri'
require 'open-uri'
doc = Nokogiri::HTML(open("http://www.bodybuilding.com/store/catalog/new-products.jsp?addFacet=REF_BRAND:BRAND_MET_RX"))
words = doc.inner_text
words.scan(/\w+/)

如果我搜索“function”这个词,我发现它在列表中出现了 20 次,但是如果我转到 http://www.bodybuilding.com/store/catalog/new-products.jsp?addFacet=REF_BRAND:BRAND_MET_RX,“function”这个词不会出现在可见文本中的任何位置。

我可以忽略 JavaScript 还是有更好的方法?

【问题讨论】:

    标签: ruby nokogiri


    【解决方案1】:

    你可以试试:

    require 'nokogiri'
    require 'open-uri'
    
    doc = Nokogiri::HTML(open("http://www.bodybuilding.com/store/catalog/new-products.jsp?addFacet=REF_BRAND:BRAND_MET_RX"))
    
    doc.traverse{ |x|
        if x.text? && x.text !~ /^\s*$/
            puts x.text
        end
    }
    

    我对 Nokogiri 做的不多,但我相信这应该会找到/输出文档中所有非空白的文本节点。这至少似乎忽略了 javascript,并且我检查的所有文本都在页面上可见(尽管其中一些在下拉菜单中)。

    【讨论】:

    • 这可行,但您应该避免在条件中使用and,因为它用于控制流并且具有与预期的&& 运算符不同的操作顺序。此外,您可以使用 !~ 运算符代替 not =~
    【解决方案2】:

    您可以忽略 JavaScript,还有更好的方法。你忽略了Nokogiri的力量。很糟糕。

    与其为您提供直接的答案,不如学习使用 Nokogiri 来“钓鱼”。

    在这样的文档中:

    <html>
      <body>
        <p>foo</p>
        <p>bar</p>
      </body>
    </html>
    

    我建议从 CSS 访问器开始,因为人们通常更熟悉它们:

    • doc = Nokogiri::HTML(var_containing_html) 将解析并返回 doc 中的 HTML DOM。
    • doc.at('p') 会返回一个 Node,它基本上指向第一个 &lt;p&gt; 节点。
    • doc.search('p') 将返回一个包含所有匹配节点的 NodeSet,其作用类似于数组,在本例中为所有 &lt;p&gt; 节点。
    • doc.at('p').text 将返回节点内的文本。
    • doc.search('p').map{ |n| n.text } 会将 &lt;p&gt; 节点中的所有文本作为文本字符串数组返回。

    随着您的文档变得越来越复杂,您需要深入研究。有时您可以使用 CSS 访问器,例如 'body p' 或类似的东西,有时您需要使用 XPaths。我不会深入这些,但那里有很棒的教程和参考资料。

    Nokogiri's tutorials 非常好。仔细阅读它们,它们会揭示你需要知道的一切。

    另外,在 Stack Overflow 上也有很多关于这类问题的回答。查看页面右侧的“相关”链接。

    【讨论】:

    • 好答案,数组的map函数以后肯定对我有用
    • 这个答案离题了,问题是要抓取整个页面的可见内部文本,而不是一堆元素。即使使用body,OP 也无法摆脱javascript 标签。
    • 离题?几乎不。 OP 没有正确使用 Nokogiri,而不是试图找到所需的节点,而是试图对所有文本进行全面抓取,并最终得到 JavaScript,即文本。相反,通过选择性地挑选所需的节点,即实际显示的节点,可以提取屏幕上的文本而不会产生任何垃圾。 OP想要一种“更好的方法来做到这一点”,这涉及理解如何正确提取数据,这就是这个答案所提供的。您的评论仅证明了我的观点。
    • Capybara 似乎有一种方法可以完全满足 OP 的要求:@session.text ...所以我认为这个问题并不疯狂。事实上,我很确定水豚是基于 nokogiri 的,所以如果这是真的,那它一定是可能的。
    【解决方案3】:

    忽略 JavaScript 所在的标签 (&lt;script&gt;)。当我们这样做的时候,我们也应该忽略 CSS (&lt;styles&gt;)。

    require 'nokogiri'
    require 'open-uri'
    
    doc = Nokogiri::HTML(URI.open("http://www.bodybuilding.com/store/catalog/new-products.jsp?addFacet=REF_BRAND:BRAND_MET_RX"))
    doc.css('style').each(&:remove)
    doc.css('script').each(&:remove)
    
    puts doc.text
    
    # Alternatively, for cleaner output:
    # puts doc.text.split("\n").map(&:strip).reject(&:empty?)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 2021-03-22
      • 2015-06-26
      相关资源
      最近更新 更多