2017-03-06 1 views
2

Je suis nouveau à Ruby et j'utilise Nokogiri pour analyser les pages Web html. Une erreur est renvoyée dans une fonction quand il arrive à la ligne:Nokogiri Lancer exception dans la fonction mais pas en dehors de la fonction

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

J'ai vérifié les entrées de la fonction, url est une chaîne avec un webaddress. La ligne que je mentionne précédemment fonctionne exactement comme prévu lorsqu'elle est utilisée en dehors de la fonction, mais pas à l'intérieur. Quand il arrive à cette ligne dans la fonction, l'erreur suivante est générée:

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

La fonction la ligne problématique est en est collé ci-dessous.

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 

Voici le programme complet (Il n'y a pas beaucoup plus):

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

D'abord, don 't explorer Wikipedia, juste ne pas. Utilisez leur API à la place. Lorsque vous écrivez un robot d'exploration, apprenez à utiliser le fichier robots.txt et à l'honorer. Aussi, limitez votre code pour être un bon citoyen du réseau ou soyez prêt à faire bannir votre code. –

+2

Ruby ne prend pas en charge la post-incrémentation ou la décrémentation ('CRAWLED_PAGES_COUNTER ++'). Vous devez utiliser '+ = 1'. En outre, vous utilisez des constantes ('CRAWLED_PAGES_COUNTER') au lieu d'une variable. Peut-être que c'est parce que vous ne comprenez pas la portée variable, mais ne le faites pas non plus. Les variables sont nommées en utilisant snake_case, pas camelCase donc 'currentPage' devrait être' current_page'. –

+0

Ne savait pas Ruby était sensible à la casse lorsqu'il s'agissait de noms de variables. Avez-vous des ressources sur le fichier robots.txt et le code de limitation? Je ne fais rien de fou avec ce code, donc je ne pensais pas que je dérangerais quiconque avec ça. – JHam

Répondre

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

Je l'ai fait et cela a fonctionné, maintenant je reçois de nouvelles erreurs. Donc le succès partiel? lol merci pour l'aide :) – JHam

+0

L'utilisation de '$' globals n'est pas la bonne solution au problème. Au lieu de cela, recommander des pratiques idiomatiques (programmation standard Ruby). –

+0

@Jam, parce que le lien que vous obtenez par exemple "/w/load.php?debug=false&lang=fr&modules=site.styles&only=styles&skin=vector" n'est pas une URL complète, veuillez vérifier pourquoi le lien que vous obtenez n'est pas complet, ou vous avez peut-être besoin d'ajouter le nom de domaine devant le lien pour en faire une URL complète pour 'open-uri' gem – Tsao

0

Juste pour vous donner quelque chose à construire à partir, c'est un simple araignée que les liens que les récoltes et les visites. Le modifier pour faire d'autres choses serait facile.

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 

Il:

  • Travaux sur http://example.com. Ce site est conçu et désigné pour l'expérimentation.
  • Vérifie si une page a déjà été visitée et ne la numérisera plus. C'est une vérification naïve et sera trompé par les URL contenant des requêtes ou des requêtes qui ne sont pas dans un ordre cohérent.
  • Vérifie si un site a déjà été visité et restreint automatiquement la récupération de page si c'est le cas. Il pourrait être berné par des alias.
  • Vérifie si une page se termine par ".htm", ".html" ou n'a pas d'extension. Tout le reste est ignoré.

Le code réel pour écrire une araignée industrielle est beaucoup plus impliqué. Les fichiers Robots.txt doivent être respectés, déterminer comment traiter les pages qui redirigent vers d'autres pages soit via des délais HTTP ou des redirections JavaScript est une tâche amusante, traiter des pages malformées est un défi ....

+0

Ceci est une réponse fantastique, va certainement utiliser http://example.com à l'avenir. Le code est une ressource fantastique, je le référencerai beaucoup dans le futur. Merci! : D – JHam

+0

Eh bien, c'est un exemple très rapide et sale. Le code pour le faire "pour des réels" est beaucoup plus complexe, et devrait impliquer une base de données pour stocker quels liens ont été visités et lesquels doivent être vérifiés. Dans une vie antérieure, j'ai écrit beaucoup d'entre eux dans le cadre de mes fonctions, et il y a beaucoup de choses à penser et de code. Dans cet exemple, Set remplace une base de données mais n'est définitivement pas persistant. –