首页 > 解决方案 > 我检查什么条件以引发自定义错误 Net::OpenTimeout 执行过期错误

问题描述

Open-uri 和 nokogiri 抓取我想要的站点的速度很慢,因此出现 Net::OpenTimeout 执行过期错误。我尝试使用救援编写自定义错误,但是我不知道我可以寻找什么条件来引发该自定义错误。

我尝试了很少的 if else 语句,但我真的只是猜到了如何检查我是否会得到那个错误。我硬编码了一个失败的条件,从而挽救了错误。我对红宝石和自定义错误非常陌生。事实上,这是我的第一次。

    class Scrape 
    Base = 'http://www.wine.com'
   @@menu = []
    @@pages = []
    def self.index
     index_url = Base + "/list/wine/7155?sortBy=savings&pricemax=90"

        #below is where I need to check for the condition to 
        raise the error

        if   doc = Nokogiri::HTML(open(index_url))



        container = doc.css('.prodList')
        wines = container.css('.prodItem')
        wines.each do |wine|
        @@menu << {
       :link => wine.css('.prodItemInfo_link').attribute('href').value,
       :name => wine.css('.prodItemInfo_name').text,
        :rating =>  (wine.css('.averageRating_average').text.to_i) > 0  ? 
      (wine.css('.averageRating_average').text) : 'no rating',
       :price => wine.css('.productPrice_price-saleWhole').text.strip
       } 

       end
       @@menu.each do |item| 
        Bottle.new.create(item)
       end
       else  
        begin
         raise Custom_error
         rescue Custom_error => error
          puts error.message 
         end
        end
       end  

       def self.scrape_page(wine_obj)

      wine_link = wine_obj.link 

       individual_page = Base + wine_link
       docu = Nokogiri::HTML(open(individual_page))
       y = docu.css('.viewMoreModule_text')
       more = docu.css('.viewMoreModule_text')

    @@pages << { 
    :obj => wine_obj,
    :name => docu.css('.pipName').text,
       :alcohol_percent =>  y

     x = docu.css('.mobileProdAttrs').css('.prodAlcoholPercent')
     y = x.css('.prodAlcoholPercent_percent').text,

     :price => docu.css('span.productPrice_price-saleWhole').text,
     :origin => docu.css('span.prodItemInfo_originText a').text, 
     :winemaker_notes => docu.css('.viewMoreModule_text').first.text,

     :more => y[2].text,
     :rating => docu.css('span.averageRating_average').first.text
    }

    Page.create_find_by_name( @@pages.last )
     end
    def self.pages 
    @@pages 
    end
    end
    class Cli 

        def run
        puts 'loading from cyberspace'

        Scrape.index
        Bottle.make_list
        controller  
    end

    def controller
        input = ''
        response = ''
        puts '                       '
        view
        while input != 11
        response = gets.chomp.to_i
        input = "#{response}11".to_i 
        if input == 111
            menu 
        elsif input == 11
            exit 
        elsif input > 0 && input < 26 
            find_by_input(input)
        elsif input != 0 && input != 111
             error_1
        end 
    end 
    end 

     def view 
        puts "welcome to the wine bar"
        puts "================="
        puts "   W   I   N   E "
        puts "      B  A  R    "
        puts "================="
        puts "                 "
        puts "type 1 for list of wine"
        puts "                       "
        puts "type 0 to exit "
    end


    def menu 
       wines = Bottle.list   
            second_input = ''                                     
            while second_input != 0 


            puts "<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>"
            puts "type the corresponding number to view more wine info"
            puts 
    "__________________________________________________________________"
                  wines.each do |wine|
            puts "#{wine.index}) #{wine.name} #{wine.price}"
                  end
            second_input = gets.chomp.to_i 
        if second_input > 0 && second_input < 26 
            find_by_input(second_input)
        elsif second_input == 0 
            exit
            second_input = 0

        elsif second_input > 25 && second_input != 101
             error_1  
        end
            end 
       puts     <<-DOC 
                the the wine number again
                    for winemaker notes

                   DOC
    end
    def find_by_input(input)
        while input != 0
       selection = Bottle.find_by_input(input) 

        puts "NAME: #{selection.name}" 
        puts "PRICE: $#{selection.price}"
        puts "RATING: #{selection.rating}"
        puts "________________________________________"        
        puts "           type #{input} again          "
        puts "           for more info                "
        puts "           provided by the winemaker    "
        # reseting input and extending user control functionality 
            third_input = ''

            third_input = gets.chomp.to_i 

       if   third_input == selection.index

            response = Scrape.scrape_page(selection)
            view_2(response, third_input)
       elsif  input == 0
            exit 
       end
    end

    end 
    def view_2(response, old_input)

        next_input = ''
        while next_input != 0
        puts "Alcohol Percent: #{response.alcohol_percent}" 
        puts "Winemaker Notes: #{response.winemaker_notes}"
        puts "                                            "
        puts "Type #{old_input} again for more!!"

        next_input = gets.chomp.to_i

        if next_input == old_input
            input = 0
            next_input = 0
            # refacort as it puts out 88 again and should not. Also 0 is not 
    exiting with correct behavior
            # refactor so looking for "#{input}"1 to prevent the recall of 
    input
            more(response)

        end
    end
    end

    def more(response)
        puts response.more 
        puts menu
    end


    def error_1
             puts "    WHOA coder    "
             puts "type a better number!" 
    end

    def exit 
        puts <<-DOC 
        well that was fun 
        Thank you for checking out 
        my first cli program 
        DOC
    end

    end  ``` 
   ```class Page 
   attr_accessor :alcohol_percent, :price, :name, :origin, :winemaker_notes, 
    :rating, :more, :obj
    @@web_pages = [] 

    def self.create_find_by_name(hash)

    if answer = @@web_pages.find{ |obj| obj.name == hash[:name]} 
        answer 
    else
        self.new.create(hash)

    end 
    end

    def create(hash)
    hash.each do |key, value|
        self.send(("#{key}="), value) 
        end 
    save
    view_more
    end
    def view_more 
        @@web_pages.last
    end

    def save 
    @@web_pages << self 
    end

    end
    attr_accessor :link, :name, :price, :rating, :index
    @@bottles = []

    def create(hash) 
        hash.each do |key, words| 
        self.send(("#{key}="), words )
        end
        save
    end


    def save 
        @@bottles << self 
    end

    def self.make_list
        @@numbered_list = @@bottles.sort{ |x,y| x.price <=> 
    y.price}.map.with_index(1) do 
             |w,i| w.index = i  
             w
     end

    end

    def self.list 
            @@numbered_list
     end 
    def self.find_by_input(input)
        a = @@numbered_list.find{ |wine| wine.index == input}
        # puts "#{a.name} $#{a.price} rating: #{a.rating}" 
        # puts "type #{input} again for winemaker notes"
        # more = ''
        # while more != 0
        # more = gets.chomp.to_i
        #      (input == more) ? (Scrape.scrape_page(a.link)) : (self.list) 

        # end
    end



    end

    class Scrape 
    Base = 'http://www.wine.com'
    @@menu = []
    @@pages = []
    def self.index
        index_url = Base + "/list/wine/7155?sortBy=savings&pricemax=90"


        if   doc = Nokogiri::HTML(open(index_url))



        container = doc.css('.prodList')
        wines = container.css('.prodItem')
        wines.each do |wine|
       @@menu << {
       :link => wine.css('.prodItemInfo_link').attribute('href').value,
       :name => wine.css('.prodItemInfo_name').text,
        :rating =>  (wine.css('.averageRating_average').text.to_i) > 0  ? 
    (wine.css('.averageRating_average').text) : 'no rating',
       :price => wine.css('.productPrice_price-saleWhole').text.strip
       } 

       end
       @@menu.each do |item| 
        Bottle.new.create(item)
       end
    else  
        begin
         raise Custom_error
         rescue Custom_error => error
          puts error.message 
         end
        end
    end  

    def self.scrape_page(wine_obj)

    wine_link = wine_obj.link 

    individual_page = Base + wine_link
    docu = Nokogiri::HTML(open(individual_page))
    y = docu.css('.viewMoreModule_text')
    more = docu.css('.viewMoreModule_text')

    @@pages << { 
    :obj => wine_obj,
    :name => docu.css('.pipName').text,
    alcholo = docu.css('.mobileProdAttrs').css('.prodAlcoholPercent'),
    :alcohol_percent => alcholo.css('.prodAlcoholPercent_percent').text,


    :price => docu.css('span.productPrice_price-saleWhole').text,
    :origin => docu.css('span.prodItemInfo_originText a').text, 
    :winemaker_notes => docu.css('.viewMoreModule_text').first.text,

    :more => y[2].text,
    :rating => docu.css('span.averageRating_average').first.text
    }

    Page.create_find_by_name( @@pages.last )
    end
    def self.pages 
    @@pages 
    end
    end

当互联网连接中断/太慢时,会引发自定义错误。

标签: rubynokogiricustom-errorsopen-uri

解决方案


当抛出异常时,程序会停止其正常流程。您需要用一个子句包围可能引发异常的代码部分begin..rescue,并尝试处理它、重新引发它或引发另一个异常。

在您的示例中,这将是:

begin
    Nokogiri::HTML(open(url))
rescue Net::OpenTimeoutError => e
    # log the error message if needed, raise your CustomError instead
    raise CustomError, e.message
end

您可以省略, 并在方法的末尾begin放置一个子句,ruby 会将其解释为好像整个方法体被包裹在一个块中,如下所示:rescuebegin..rescue

def open_page(url)
    return Nokogiri::HTML(open(url))
rescue Net::OpenTimeoutError => e
    raise CustomError, e.message
end

推荐阅读