如何解析相关数据并将值存储到数据库

时间:2017-04-06 13:46:36

标签: ruby-on-rails ruby nokogiri

我试图通过网页进行解析,收集值并将其存储到数据库中。

这是我的代码,带有注释掉的数据库代码:

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

以下是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>

我无法按顺序循环并存储到数据库。这是当前的输出:

++++++ 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

这是预期的输出:

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对应的颜色名称数据库?

1 个答案:

答案 0 :(得分:1)

如果我想要这些数据,我会做什么:

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>

当与:

一起使用时
data.each do |k, v|
  puts "hex_code: %s\ncolor_name: %s" % [k, v]
end

会输出:

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

但是,互联网上有这些关联的表格。我不建议解析一个并尝试将其注入数据库表,而是建议找一个并创建一个模块或类,将数据存储为常量或哈希值,这样您就不必点击数据库来提取价值。如果您正在使用这些值来设置页面中的颜色,或者即使您将值的相关性呈现给颜色名称,您也希望能够以最快的速度访问。或者创建一个已经呈现的静态页面,因为这些关联和定义不会改变。

数据库对某些事情很有用,但这对它来说似乎不是一个好时机。

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

是残酷的。

从字符串中提取十六进制代码是字符串切片或正则表达式的一个很好的应用程序。你可以采取多种方式:

style = "background-color:#EEEFF4;"

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

使用切片[-8..-2]可能是最容易出错的,因为它假定值总是六个字符长,颜色的十六进制值不必是。例如,#FFF相当于#FFFFFF,因此处理三个或六个字符变体非常重要。

在我上面的示例中,我使用/#([^;]+);$/并不像/(#\h{3,6});$/那样简洁,但他们都有权衡,所以如果你想使用正则表达式,请选择。它们的工作方式是让你弄清楚,只要记住,并非所有东西都是用黄金正则表达式敲击数据的机会;当他们成为最好的工具时使用它们,因为它们可以打开通往黑暗的大门并迎来虫子的主。

而且,我故意排除了十六进制值中的#。添加它会浪费冗余字符上的空间以进行查找和表格,但您的里程可能会有所不同。