如何在课堂内避免多个Nokogiri请求?

时间:2013-08-11 13:42:36

标签: ruby-on-rails ruby

我正在研究一个宝石。 这是它的主页: https://github.com/scaryguy/vakit

如果您查看源代码,您可以看到我正在解析外部HTML页面以从中过滤一些数据。

问题是,尽管我每次拨打Vakit.sabahVakit.oglen新请求时都会通过一个请求获取我想要的所有数据。

require "vakit/version"
require 'vakit/connect'
require 'Nokogiri'
require 'open-uri'

module Vakit

  def self.today
    Vakit::Connect.shaber
  end

  def self.imsak
    Vakit::Connect.shaber[:imsak]
  end

  def self.sabah
    Vakit::Connect.shaber[:sabah]
  end

  def self.oglen
    Vakit::Connect.shaber[:oglen]
  end

  def self.ikindi
    Vakit::Connect.shaber[:ikindi]
  end

  def self.aksam
    Vakit::Connect.shaber[:aksam]
  end

  def self.yatsi
    Vakit::Connect.shaber[:yatsi]
  end

end

我认为这不是一种有效的方式。

我应该能够在没有新请求的情况下访问我的哈希的属性,不应该吗?

module Vakit
class Connect
    def initialize(opt={})
        @path = opt[:path]
    end

    def self.shaber
        doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/'))
        x = doc.css('#hnmzT')

        times = []
        x.each do |vakit|
            data = vakit.children.first.children.last.content
            data_add = data.slice(0..data.length-2)
            times.push(data_add)
        end
        times
        vakit = {

            imsak: times[0],
            sabah: times[1],
            oglen: times[2],
            ikindi: times[3],
            aksam: times[4],
            yatsi: times[5]


        }

    end

end
end

我需要一些启发。

3 个答案:

答案 0 :(得分:1)

每次使用shaber时,您都明确open并重新分析内容。您没有尝试本地存储内容或解析的DOM,并检查您是否已经拥有它。

而不是doc =使用@@doc ||=并将doc的出现次数更改为@@doc

||=运算符仅在@@doc为空时分配。一旦它被分配到非零或非假值,它将不再触发,因此它是一个穷人“记忆”。

因为您使用的是类方法,所以我建议使用类变量。如果您有多个正在查看不同页面的类实例,@@doc可能是实例变量@doc。原样,这不会产生任何影响,因为您只对一个页面进行了硬编码,但对于未来的代码增长,它可能会有用。


您为访问该页面而编写的代码并不是非常惯用的Ruby。我写的更像是以下内容,因为URL没有返回具有足够时间值的页面,所以它不起作用:

require 'nokogiri'
require 'open-uri'

module Vakit

  URL = 'http://www.samanyoluhaber.com/'

  class Connect
    def initialize(opt={})
      @path = opt[:path]
      @url = opt[:url] || URL
    end

    def shaber(url=nil)
      doc = Nokogiri::HTML(open(url || @url))
      doc.at_css('#hnmzT').to_html # => "<li id=\"hnmzT\" name=\"imsak\"><a id=\"at\"><span>\u0130msak:</span>4:22\u00A0</a></li>"

      x = doc.at_css('li#hnmzT a')
      x.to_html # => "<a id=\"at\"><span>\u0130msak:</span>4:22\u00A0</a>"

      times = x.text.scan(/\d+:\d+/)

      Hash[[:imsak, :sabah, :oglen, :ikindi, :aksam, :yatsi].zip(times)]
    end

  end
end

connection = Vakit::Connect.new
connection.shaber # => {:imsak=>"4:22", :sabah=>nil, :oglen=>nil, :ikindi=>nil, :aksam=>nil, :yatsi=>nil}

Connect不是一个好名字。一个类是一个对象,一个东西。 Connect是动词,是事物发生或发生的事情。 connect对于方法来说是一个好名字。

答案 1 :(得分:0)

这一行 doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/'))正在多次拨打请求的电话。

我用你的宝石测试了这个,这似乎有效。

if @doc.nil?
  @doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/'))
end

另外在vakit.rb中更改

require 'Nokogiri' to require 'nokogiri'(简单n)

答案 2 :(得分:0)

我将提出以下建议:

  1. Vakit::Connect应该是类中的实例方法。所以它可以实例化&amp;保存在记忆中。这样每个请求将是同一对象的不同实例。如果班级不存在。创造它。
  2. 使用memorization来缓存代价高昂的操作。
  3. 如果操作需要很长时间,比如大于3秒。将其转换为后台工作&amp;使用工人来处理它们。但是,因为你正在创作一个宝石。我认为这个责任应该发挥给使用gem的开发者。
  4. 所以我会这样做: 连接类:

    module Vakit
    class Connect
    attr_accessor :path, :doc
    def initialize(opt={}, url)
      @path = opt[:path]
      @doc = Nokogiri::HTML(open(url))
    end
    
    def shaber
     x = @doc.css('#hnmzT')
      #no changes here
    end
    end
    

    Vakit模块

    module Vakit
     class Main #name it something more meaningful   
      def initialize(opt={})
       @connected = Connect.new(opt[:path], 'http://www.samanyoluhaber.com/')
      end
      def today
       @connected.shaber
      end
    
      def imsak
       today[:imsak]
      end
    
      def sabah
       today[:sabah]
      end
    
      def oglen
       today[:oglen]
      end
    
      def ikindi
       today[:ikindi]
      end
    
      def aksam
       today[:aksam]
      end
    
      def yatsi
       today[:yatsi]
      end
    
    end
    

    然后在代码中,您可以像这样使用它:

    @v = Vakit::Main.new
    @v.aksam
    

    这可能不是100%完美,因为我真的不明白你的代码的目的,哦明白它的作用但不是为什么。但是每次访问哈希时,这都不会产生新的请求。