2017-03-06 27 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代替了一个数据库,但它绝对不是持久的。 –

相关问题