2017-03-06 28 views
2

我是Ruby新手,正在使用Nokogiri來解析html網頁。錯誤在函數拋出當它到達線路:Nokogiri在函數中拋出異常但不在函數外

currentPage = Nokogiri::HTML(open(url))

我已經驗證功能的輸入,網址是一個webaddress的字符串。我之前提到的這一行在函數外部使用時完全按照預期工作,但不在裏面。當它到達該行的函數內部拋出以下錯誤:

WebCrawler.rb:25:in `explore': undefined method `[email protected]' for #<Nokogiri::HTML::Document:0x007f97ea0cdf30> (NoMethodError) 
from WebCrawler.rb:43:in `<main>' 

功能有問題的線是在下面粘貼。

def explore(url) 
    if CRAWLED_PAGES_COUNTER > CRAWLED_PAGES_LIMIT 
      return 
    end 
    CRAWLED_PAGES_COUNTER++ 

    currentPage = Nokogiri::HTML(open(url)) 
    links = currentPage.xpath('//@href').map(&:value) 

    eval_page(currentPage) 

    links.each do|link| 
      puts link 
      explore(link) 
    end 
end 

下面是完整的程序(這不是更長的時間):

require 'nokogiri' 
require 'open-uri' 

#Crawler Params 
START_URL = "https://en.wikipedia.org" 
CRAWLED_PAGES_COUNTER = 0 
CRAWLED_PAGES_LIMIT = 5 

#Crawler Functions 
def explore(url) 
    if CRAWLED_PAGES_COUNTER > CRAWLED_PAGES_LIMIT 
      return 
    end 
    CRAWLED_PAGES_COUNTER++ 

    currentPage = Nokogiri::HTML(open(url)) 
    links = currentPage.xpath('//@href').map(&:value) 

    eval_page(currentPage) 

    links.each do|link| 
      puts link 
      explore(link) 
    end 
end 

def eval_page(page) 
    puts page.title 
end 

#Start Crawling 


explore(START_URL) 
+2

首先,不要爬行維基百科,不要。改用他們的API。在編寫爬網程序時,請學習使用robots.txt文件並遵守它。此外,限制你的代碼是一個好的網絡公民或準備禁止你的代碼。 –

+2

Ruby不支持後遞增或遞減('CRAWLED_PAGES_COUNTER ++')。你必須使用'+ = 1'。另外,你正在使用常量('CRAWLED_PAGES_COUNTER')而不是一個變量。也許這是因爲你不瞭解變量範圍,但也不這樣做。變量是用snake_case命名的,而不是camelCase,所以'currentPage'應該是'current_page'。 –

+0

不知道Ruby在變量名稱時區分大小寫。你有沒有robots.txt和限制代碼的資源?我沒有對這段代碼做任何瘋狂的事情,所以我不認爲我會用它來打擾任何人。 – JHam

回答

0
require 'nokogiri' 
require 'open-uri' 

#Crawler Params 
$START_URL = "https://en.wikipedia.org" 
$CRAWLED_PAGES_COUNTER = 0 
$CRAWLED_PAGES_LIMIT = 5 

#Crawler Functions 
def explore(url) 
    if $CRAWLED_PAGES_COUNTER > $CRAWLED_PAGES_LIMIT 
      return 
    end 
    $CRAWLED_PAGES_COUNTER+=1 

    currentPage = Nokogiri::HTML(open(url)) 
    links = currentPage.xpath('//@href').map(&:value) 

    eval_page(currentPage) 

    links.each do|link| 
      puts link 
      explore(link) 
    end 
end 

def eval_page(page) 
    puts page.title 
end 

#Start Crawling 


explore($START_URL) 
+0

我做到了這一點,它的工作,現在我得到新的錯誤。部分成功?大聲笑感謝您的幫助:) – JHam

+0

使用'$'全局變量不是解決問題的正確方法。相反,推薦使用慣用的(Ruby標準編程)實踐。 –

+0

@JHam,因爲例如「/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=vector」的鏈接不是完整的網址,請檢查您獲得的鏈接不完整的原因,或者您可能需要在鏈接前添加域名,以使其成爲「open-uri」gem的完整網址 – Tsao

0

只是爲了給你的東西從建立,這是一個簡單的蜘蛛,只有收成和訪問鏈接。修改它來做其他事情會很容易。

require 'nokogiri' 
require 'open-uri' 
require 'set' 

BASE_URL = 'http://example.com' 
URL_FORMAT = '%s://%s:%s' 
SLEEP_TIME = 30 # in seconds 

urls = [BASE_URL] 
last_host = BASE_URL 
visited_urls = Set.new 
visited_hosts = Set.new 

until urls.empty? 
    this_uri = URI.join(last_host, urls.shift) 
    next if visited_urls.include?(this_uri) 

    puts "Scanning: #{this_uri}" 

    doc = Nokogiri::HTML(this_uri.open) 
    visited_urls << this_uri 

    if visited_hosts.include?(this_uri.host) 
    puts "Sleeping #{SLEEP_TIME} seconds to reduce server load..." 
    sleep SLEEP_TIME 
    end 

    visited_hosts << this_uri.host 

    urls += doc.search('[href]').map { |node| 
    node['href'] 
    }.select { |url| 
    extension = File.extname(URI.parse(url).path) 
    extension[/\.html?$/] || extension.empty? 
    } 

    last_host = URL_FORMAT % [:scheme, :host, :port].map{ |s| this_uri.send(s) } 
    puts "#{urls.size} URLs remain." 
end 

它:

  • 作品上http://example.com。該網站是爲實驗而設計和指定的。
  • 檢查以前是否訪問過一個頁面,並且不會再次掃描它。這是一個天真的檢查,並會被包含查詢或查詢的網址愚弄,這些查詢或查詢的順序不一致。
  • 檢查以前是否訪問過一個站點,如果是,則自動限制頁面檢索。它可能被別名愚弄。
  • 檢查頁面是以「.htm」,「.html」結尾還是沒有擴展名。其他任何被忽略。

編寫工業強度蜘蛛的實際代碼涉及更多。 robots.txt文件需要得到尊重,弄清楚如何處理重定向到其他頁面的頁面,通過HTTP超時或JavaScript重定向是一項有趣的工作,處理格式不正確的頁面是一項挑戰....

+0

這是一個非常棒的迴應,將來肯定會使用http://example.com。代碼是一個很好的資源,我將來會參考它。謝謝! :D – JHam

+0

嗯,這是一個非常快速和骯髒的例子。要做到「真實」的代碼要複雜得多,並且應該包含一個數據庫來存儲訪問哪些鏈接以及需要檢查哪些鏈接。在過去的一段時間裏,我寫了很多作爲我工作職責的一部分,還有很多事情要考慮和編寫。在這個例子中,Set代替了一個數據庫,但它絕對不是持久的。 –

相關問題