使用Ruby风格的Couting html标签(inject,blocks,each..)



我想统计某个页面中几个html标签的出现次数。我可以用经典的方式,但我正在尝试用Ruby的方式。

这就是我所做的,但它不是将每个部分计数相加,而是用列表的元素创建一个字符串:

tags = [ '<img>', '<script>', '<applet>', '<video>', '<audio>' ]
weight = tags.each { |tag| web.to_s.scan(/#{tag}/).length }.inject(:+)

有什么建议吗?

编辑:

def browse startpage, depth, block
    if depth > 0
        begin 
            web = open(startpage).read
            block.call startpage, web
        rescue
            return
        end
        links = URI.extract(web)
        links.each { |link| browse link, depth-1, block } 
    end
end
browse("https://www.youtube.com/", 2, lambda { |page_name, web|
    tags = [ '<img>', '<script>', '<applet>', '<video>', '<audio>' ]
    web.force_encoding 'utf-8'
    parsed_string = Nokogiri::HTML(web)
    weight = tags.each_with_object(Hash.new(0)) do |tag, hash|
      occurrences = parsed_string.xpath("//#{tag.gsub(/[<>]/, '')}").length
      hash[tag] = occurrences
    end
    puts "Page weight for #{web.base_uri} = #{weight}"
})

这里有一种解决问题的方法:

web = "<audio> <audio> <video>" # I guess 'web' is other than a string in your example, so the need for to_s below
tags = [ '<img>', '<script>', '<applet>', '<video>', '<audio>' ]
tag_occurrences = tags.each_with_object(Hash.new(0)) do |tag, hash|
  occurrences = web.to_s.scan(/#{tag}/).length
  hash[tag] = occurrences
end
p tag_occurrences #=> {"<img>"=>0, "<script>"=>0, "<applet>"=>0, "<video>"=>1, "<audio>"=>2}

不过,不建议您使用正则表达式来匹配标记。一个更好的方法是使用像Nokogiri这样的东西来计数标签:

require 'nokogiri'
web = "<audio> <audio> <video>" 
parsed_string = Nokogiri::HTML(web.to_s) #using to_s because I'm assuming web isn't an actual string in your code
tags = [ '<img>', '<script>', '<applet>', '<video>', '<audio>' ]
tag_occurrences = tags.each_with_object(Hash.new(0)) do |tag, hash|
  occurrences = parsed_string.xpath("//#{tag.gsub(/[<>]/, '')}").length
  hash[tag] = occurrences
end
p tag_occurrences #=> {"<img>"=>0, "<script>"=>0, "<applet>"=>0, "<video>"=>1, "<audio>"=>2}

关于你的评论,我在YouTube上使用了这个(使用我的第二段代码来处理数据),得到了:

require 'open-uri'
web = open('http://youtube.com').read
# the code above to parse web using Nokogiri
p tag_occurrences #=> {"<img>"=>151, "<script>"=>13, "<applet>"=>0, "<video>"=>0, "<audio>"=>0}

我会traverse文档一次,计算节点名称:

doc = Nokogiri::HTML(open('https://www.youtube.com/'))
tags_count = Hash.new(0)
doc.traverse { |node| tags_count[node.name] += 1 }
tags_count
#=> {"html"=>2, "#cdata-section"=>12, "script"=>15, "text"=>7958, "link"=>11, "title"=>1, "meta"=>4, "comment"=>18, "head"=>1, "div"=>1152, "input"=>2, "form"=>2, "img"=>135, "span"=>2878, "a"=>397, "button"=>434, "label"=>1, "li"=>740, "ul"=>265, "hr"=>3, "h3"=>117, "p"=>48, "br"=>3, "strong"=>2, "ol"=>1, "h2"=>26, "b"=>5, "body"=>1, "document"=>1}

最新更新