2017-04-06 3 views
0

J'essaie d'analyser une page Web, de collecter des valeurs et de les stocker dans une base de données.Comment analyser les données associées et stocker les valeurs dans la base de données

Voici mon code avec le code de base de données en commentaire:

require 'nokogiri' 
require 'open-uri' 

doc = Nokogiri::HTML(open("https://example.com/colors")) 
colors = doc.css(".colorCircle") 
colors_name = doc.css(".zw-m-c-txt")  

colors.each do |ele| 
    hex_code = ele.attr('style').split(";").first.split(":").last  

    colors_name.each do |name| 
     color_name = name.text 
     puts " ++++++ hex_code #{hex_code}" 
     puts " ++++++ color_name #{color_name}" 
     # color = colors.find_by(:hex_code => hex_code) 
     # if color.present? 
     #    color.update_attributes(:name => color_name) 
     #   else 
     #    model.colors.create(:name => color_name, :hex_code => hex_code) 
     #   end 
    end 
end 

Voici le détail de la page HTML:

<span class="colorCircle" style="background-color:#EEEFF4;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> White Orchid Pearl </span></p> 
<span class="colorCircle" style="background-color:#ACABB0;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Modern Steel Metallic </span></p> 
<span class="colorCircle" style="background-color:#220909;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Golden Brown Metallic </span></p> 
<span class="colorCircle" style="background-color:#43161b;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Carnelian Red Pearl </span></p> 
<span class="colorCircle" style="background-color:#E8F1FA;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Alabaster Silver </span></p> 

Je ne suis pas en mesure de boucle à travers elle de façon séquentielle et stocker à la base de données. Voici la sortie de courant:

++++++ color_name White Orchid Pearl 
++++++ hex_code #EEEFF4 
++++++ color_name White Orchid Pearl 
++++++ hex_code #ACABB0 
++++++ color_name White Orchid Pearl 
++++++ hex_code #220909 
++++++ color_name White Orchid Pearl 
++++++ hex_code #43161b 
++++++ color_name White Orchid Pearl 
++++++ hex_code #E8F1FA 
++++++ color_name Modern Steel Metallic 
++++++ hex_code #EEEFF4 
++++++ color_name Modern Steel Metallic 
++++++ hex_code #ACABB0 
++++++ color_name Modern Steel Metallic 
++++++ hex_code #220909 
++++++ color_name Modern Steel Metallic 
++++++ hex_code #43161b 
++++++ color_name Modern Steel Metallic 

Ceci est le résultat attendu:

hex_code  #EEEFF4 
color_name White Orchid Pearl 
hex_code  #ACABB0 
color_name Modern Steel Metallic 
hex_code  #220909 
color_name Golden Brown Metallic 

Comment puis-je obtenir la sortie attendue et l'enregistrer dans une base de données correspondante hex_code avec le nom de la couleur?

+0

Vous voulez donc associer chaque nom de couleur à la couleur de fond de l'intervalle? Par exemple. Perle d'orchidée blanche aveC# EEEFF4? – radubogdan

+0

Vous vous rendez compte que vous avez deux boucles imbriquées et que vous exécutez essentiellement chaque nom_color pour chaque couleur. – radubogdan

+0

@radubogdan Oui, vous avez raison, je veux associer chaque nom de couleur à bkg-color depuis span. –

Répondre

1

Voici ce que je ferais si je voulais que les données:

require 'nokogiri' 

doc = Nokogiri::HTML(DATA.read) 

data = doc.search('.colorCircle').map { |span| 
    hex = span['style'][/#([^;]+);$/, 1] 
    color = span.next_element.at('span').text.strip 
    [ hex, color ] 
}.to_h 
# => {"EEEFF4"=>"White Orchid Pearl", 
#  "ACABB0"=>"Modern Steel Metallic", 
#  "220909"=>"Golden Brown Metallic", 
#  "43161b"=>"Carnelian Red Pearl", 
#  "E8F1FA"=>"Alabaster Silver"} 

__END__ 
<span class="colorCircle" style="background-color:#EEEFF4;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> White Orchid Pearl </span></p> 
<span class="colorCircle" style="background-color:#ACABB0;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Modern Steel Metallic </span></p> 
<span class="colorCircle" style="background-color:#220909;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Golden Brown Metallic </span></p> 
<span class="colorCircle" style="background-color:#43161b;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Carnelian Red Pearl </span></p> 
<span class="colorCircle" style="background-color:#E8F1FA;"></span> 
<p class="zw-m-c-txt"> <span class="fnt-14"> Alabaster Silver </span></p> 

qui, lorsqu'il est utilisé avec:

data.each do |k, v| 
    puts "hex_code: %s\ncolor_name: %s" % [k, v] 
end 

génèrerait:

hex_code: EEEFF4 
color_name: White Orchid Pearl 
hex_code: ACABB0 
color_name: Modern Steel Metallic 
hex_code: 220909 
color_name: Golden Brown Metallic 
hex_code: 43161b 
color_name: Carnelian Red Pearl 
hex_code: E8F1FA 
color_name: Alabaster Silver 

Mais, il y a tables partout sur Internet avec ces associations. Plutôt qu'analyser un et essayer de l'injecter dans une table de base de données, je vous recommande de trouver un et créer un module ou une classe qui stocke les données comme constantes ou hachages afin que vous n'ayez pas à frapper la base de données pour extraire les valeurs. Vous voulez l'accès le plus rapide possible si vous utilisez ces valeurs pour définir des couleurs dans les pages, ou même si vous présentez les corrélations des valeurs aux noms de couleur. Ou créez une page statique qui est déjà rendue, car ces associations et définitions ne vont pas changer.

Les bases de données sont excellentes pour certaines choses, mais cela ne semble pas être un bon moment pour cela.


Ce

ele.attr('style').split(";").first.split(":").last 

est brutale.

Extraire le code hexadécimal de la chaîne est une excellente application pour le découpage de chaînes ou une expression régulière. Vous pouvez le faire de plusieurs façons:

style = "background-color:#EEEFF4;" 

style.split(':').last.chop # => "#EEEFF4" 
style[-8..-2] # => "#EEEFF4" 
style[/(#\h{3,6});$/, 1] # => "#EEEFF4" 

En utilisant une tranche [-8..-2] est probablement la plus sujette à l'erreur, car il prend la valeur est toujours six caractères, dont les valeurs hexagonales pour les couleurs ne doivent pas être. Par exemple, #FFF équivaut à #FFFFFF, donc la gestion de trois ou six variantes de caractères est importante. Dans mon exemple ci-dessus j'ai utilisé /#([^;]+);$/ qui n'est pas aussi concis que /(#\h{3,6});$/, mais ils ont tous deux des compromis, alors faites votre choix si vous voulez utiliser une regex.Et comment ils fonctionnent est pour vous de comprendre, rappelez-vous juste que tout n'est pas une occasion de frapper les données avec le marteau d'expression régulière doré; Utilisez-les quand ils sont le meilleur outil, car ils peuvent ouvrir la porte aux ténèbres et inaugurer le seigneur des insectes.

Et, j'ai délibérément exclu le # dans les valeurs hexadécimales. L'ajouter gaspille de l'espace sur un caractère redondant pour les recherches et dans les tables, mais votre kilométrage peut varier.

+0

Merci @theTinMan, très belle explication. –

+0

votre code fonctionne si je lis les données de DATA.read cependant si j'essaye de lire des données directement du Web j'obtiens l'erreur suivant. »Dans le bloc dans

: méthode non définie« à »pour nil: NilClass (NoMethodError)' a remarqué que ' span' ne contient qu'une seule ligne '' elle ne contient pas les balises suivantes. J'ai donc essayé de spécifier deux classes dans la recherche 'data = doc.search ('. ColorCircle, .zw-m-c-txt'). Map' toujours obtenir l'erreur ci-dessus. pourriez-vous s'il vous plaît me guider là où ça ne va pas. –

+0

Je ne peux pas vous aider puisque je n'ai aucune idée d'où vous lisez les données. "[mcve]" indique que vous avez besoin d'un exemple d'entrée minimal dans la question qui illustre le problème que j'ai utilisé, donc le code HTML que vous avez donné n'était peut-être pas exact. Je vous recommande d'utiliser 'nokogiri' sur la ligne de commande et de lui transmettre l'URL que vous utilisez, puis de voir si vous pouvez trouver le nœud que vous recherchez. Il se peut que la page utilise DHTML et que seuls les navigateurs puissent le trouver. –