2017-03-06 24 views
2

Rubyを初めて使用しています.Nokogiriを使用してhtml Webページを解析しています。それはラインになったときにエラーが関数にスローされます。私は、関数の入力を検証したNokogiri関数内で例外をスローしますが、関数外ではありません

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

、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')を使用しています。おそらくそれはあなたが変数スコープを理解していないからですが、どちらもしません。変数はcamelCaseではなくsnake_caseを使って命名されるので、 '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"というリンクは完全なURLではないので、あなたが得たリンクが完全でない理由を確認してください。または、おそらくあなたは 'open-uri' gemの完全なURLになるようにリンクの前にドメイン名を追加する必要があります – 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

  • 作品。そのサイトは実験のために設計され、指定されています。
  • ページが以前に訪問されたかどうかを確認し、再度スキャンしません。これは簡単なチェックであり、一貫した順序ではないクエリやクエリを含むURLにだまされます。
  • 以前にサイトにアクセスしたかどうかを確認し、その場合は自動的にページ取得を抑制します。エイリアスに惑わされる可能性があります。
  • ページが ".htm"、 ".html"で終わるかどうか、または拡張子がないかどうかを確認します。それ以外は無視されます。

工業用スパイダーを書くための実際のコードは、はるかに関与しています。 Robots.txtファイルは、HTTPタイムアウトやJavaScriptリダイレクトを経由して他のページにリダイレクトされるページを処理する方法を理解する必要があり、楽しい作業です。不正なページを扱うのは難しい課題です...

+0

これは素晴らしい応答です。将来的にはhttp://example.comを使用しています。コードは素晴らしいリソースです、私は将来それをたくさん参照しています。ありがとう! :D – JHam

+0

さて、それは非常に迅速かつ汚れた例です。 「真実のために」行うコードははるかに複雑で、どのリンクが訪問されたかをチェックする必要があるデータベースを格納する必要があります。以前の人生では、私は職務の一環としてそれらをたくさん書いていました。考えてコードすることはたくさんあります。この例では、Setはデータベースを代用していますが、永続的ではありません。 –

関連する問題