2017-03-06 7 views
2

저는 Ruby를 처음 사용하고 있으며, Nokogiri를 사용하여 html 웹 페이지를 구문 분석하고 있습니다. 이 선에 도달 할 때 오류가 함수에서 발생합니다 : 나는 함수의 입력을 확인했습니다Nokogiri 함수에서 예외를 throw하지만 함수 외부에 있지 않습니다.

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

, URL은 webaddress있는 문자열입니다. 앞에서 언급 한 선은 함수 외부에서 사용될 때는 의도 한대로 작동하지만 내부에서는 사용되지 않습니다. 함수 내에서 해당 줄을 가져 오면 다음 오류가 throw됩니다.

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

'$'globals를 사용하는 것이 문제의 올바른 해결책이 아닙니다. 대신 관용적 인 (Ruby 표준 프로그래밍) 방법을 권장합니다. –

+0

@JHam 예를 들어 "/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=vector"링크가 완전한 URL이 아니기 때문에 링크가 완료되지 않은 이유를 확인하십시오. 아니면 URL 앞에 'open-uri'라는 완전한 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 타임 아웃이나 자바 스크립트 리디렉션을 통해 다른 페이지로 리디렉션되는 페이지를 처리하는 방법을 알아 내야하며, 조작 된 페이지를 다루는 것은 재미있는 작업입니다.

+0

이것은 환상적인 답변이며 앞으로도 http://example.com을 사용하게 될 것입니다. 이 코드는 환상적인 리소스입니다. 앞으로 많이 참조 할 것입니다. 감사! : D – JHam

+0

글쎄, 아주 빠르고 더러운 예입니다. "실제를위한"코드는 훨씬 더 복잡하며 방문한 링크와 확인해야 할 데이터베이스를 저장하는 데이터베이스가 있어야합니다. 이전의 삶에서 나는 그들의 직무의 일환으로 많은 것을 썼다. 생각하고 코딩하는 것이 많이있다. 이 예제에서 Set은 데이터베이스를 대체하지만 영구적이지는 않습니다. –