通过Nokogiri获取可查看的文字

时间:2011-05-25 18:51:59

标签: ruby nokogiri

我想打开一个包含Nokogiri的网页,并提取用户在浏览器中访问该页面时看到的所有单词并分析单词频率。

使用nokogiri从html文档中获取所有可读单词的最简单方法是什么?理想的代码片段将采用html页面(比如文件),并提供一系列单个单词,这些单词来自可读的所有类型的元素。

(无需担心javascript或css隐藏元素,从而隐藏单词;只需设计用于显示的所有单词都可以。)

3 个答案:

答案 0 :(得分:12)

您需要Nokogiri::XML::Node#inner_text方法:

require 'nokogiri'
require 'open-uri'
html = Nokogiri::HTML(open 'http://stackoverflow.com/questions/6129357')

# Alternatively
html = Nokogiri::HTML(IO.read 'myfile.html')

text  = html.at('body').inner_text

# Pretend that all words we care about contain only a-z, 0-9, or underscores
words = text.scan(/\w+/)
p words.length, words.uniq.length, words.uniq.sort[0..8]
#=> 907
#=> 428
#=> ["0", "1", "100", "15px", "2", "20", "2011", "220px", "24158nokogiri"]

# How about words that are only letters?
words = text.scan(/[a-z]+/i)
p words.length, words.uniq.length, words.uniq.sort[0..5]
#=> 872
#=> 406
#=> ["Answer", "Ask", "Badges", "Browse", "DocumentFragment", "Email"]
# Find the most frequent words
require 'pp'
def frequencies(words)
  Hash[
    words.group_by(&:downcase).map{ |word,instances|
      [word,instances.length]
    }.sort_by(&:last).reverse
  ]
end
pp frequencies(words)
#=> {"nokogiri"=>34,
#=>  "a"=>27,
#=>  "html"=>18,
#=>  "function"=>17,
#=>  "s"=>13,
#=>  "var"=>13,
#=>  "b"=>12,
#=>  "c"=>11,
#=>  ...

# Hrm...let's drop the javascript code out of our words
html.css('script').remove
words = html.at('body').inner_text.scan(/\w+/)
pp frequencies(words)
#=> {"nokogiri"=>36,
#=>  "words"=>18,
#=>  "html"=>17,
#=>  "text"=>13,
#=>  "with"=>12,
#=>  "a"=>12,
#=>  "the"=>11,
#=>  "and"=>11,
#=>  ...

答案 1 :(得分:4)

如果你真的想用Nokogiri这样做(你可以用其他方法只使用正则表达式来删除标签),那么你应该:

  1. doc = Nokogiri :: HTML(open('url')。read)#open-uri
  2. 使用doc.search('script')之类的东西去除所有javascript和样式标签。每个{| el | el.unlink}
  3. doc.text

答案 2 :(得分:0)

更新:从ruby 2.7开始-有一种新的Enumerable方法-tally-计算发生次数

输入所选答案: html.at('body')。inner_text-将合并所有节点中的所有文本-不带空格。例如包含以下内容的文档:

<html><body><p>this</p><p>text</p></body><html>

将导致“此文本”

更好:使用this answer

html = Nokogiri::HTML(open 'http://stackoverflow.com/questions/6129357')
text = html.xpath('.//text() | text()').map(&:inner_text).join(' ')
occurrences = text.scan(/\w+/).map(&:downcase).tally