2014-06-18 59 views
0

我正在从网站上刮取以下数据的网络抓取工具。如何将数据保存到多维Ruby哈希,然后将哈希转换为单个JSON文件?

  • 集团
  • 类别
  • 搜索属性

我用下面的代码保存数据为三个独立的(一维)JSON文件:

require 'mechanize' 

@raw_groups_array = [] 
@raw_categories_array = [] 
@search_attributes = [] 

@groups_clean = [] 
@categories_clean = [] 

@categories_combined = [] 

@categories_hash = {} 

# Initialize Mechanize object 
a = Mechanize.new 

# Begin magic 
a.get('http://www.marktplaats.nl/') do |page| 
    groups = page.search('//*[(@id = "navigation-categories")]//a') 
    groups.each do |group| 
    @raw_groups_array.push(group) 
    @groups_clean.push(group.text) 

    a.get(group[:href]) do |page_2| 
     categories = page_2.search('//*[(@id = "category-browser")]//a') 
     categories.each do |category| 
     @raw_categories_array.push(category) 
     @categories_clean.push(category.text) 
     @categories_combined.push("#{group.text} | #{category.text}") 

     a.get(category[:href]) do |page_3| 
      search_attributes = page_3.search('//*[contains(concat(" ", @class, " "), concat(" ", "heading", " "))]') 

      search_attributes.each do |attribute| 
      @search_attributes.push("#{group.text} | #{category.text} | #{attribute.text}") unless attribute.text == 'Outlet ' 

      # Uncomment the line below if you want to see what's going on. 
      # (it has minimal effect on performance) 
      puts "#{group.text} | #{category.text} | #{attribute.text}" unless attribute.text == 'Outlet ' 
      end 
     end 
     end 
    end 
    end 
end 

# Write json files 
File.open('json/prestige/prestige_groups.json', 'w') do |f| 
    puts '# Writing groups' 
    f.write(@groups_clean.to_json) 
    puts '|-----------> Done.' 
end 

File.open('json/prestige/prestige_categories.json', 'w') do |f| 
    puts '# Writing categories' 
    f.write(@categories_clean.to_json) 
    puts '|-----------> Done.' 
end 

File.open('json/prestige/prestige_combined.json', 'w') do |f| 
    puts '# Writing combined' 
    f.write(@categories_combined.to_json) 
    puts '|-----------> Done.' 
end 

File.open('json/prestige/prestige_search_attributes.json', 'w') do |f| 
    puts '# Writing search attributes' 
    f.write(@search_attributes.to_json) 
    puts '|-----------> Done.' 
end 

puts '# Finished.' 

代码起作用。但我有一个很难重构它采用以下格式创建Ruby哈希:

{ 
    "category"=>{ 
    "name"=>"#{category}", 
    "group"=>"#{group}", 
    "search_attributes"=>{ 
     "1"=>"#{search_attributes[0]}", 
     "2"=>"#{search_attributes[1]}", 
     "."=>"#{search_attributes[.]}", 
     "i"=>"#{search_attributes[i]}", # depending on search_attributes.length 
    } 
    } 
} 

我已经试过了诸如:

... 
search_attributes.each do |attribute| 
    @categories_hash.store([:category][:name], category.text) 
    @categories_hash.store([:category][:group], group.text) 
    @categories_hash.store([:category][:search_attributes][:1], attribute.text) 
end 
... 

但不断收到语法错误。

任何帮助,将不胜感激。

更新

马克斯建议我尝试Hash#[]但这返回一个哈希与单一类别(最后一个)。

search_attributes.each_with_index do |attribute, index| 
    @categories_hash[:category][:name] = category.text 
    @categories_hash[:category][:group] = group.text 
    @categories_hash[:category][:search_attributes][:"#{index}"] = attribute.text unless attribute.text == "Outlet " 
end 

我已粘贴完整密码here

+0

我不认为你了解混编工作。哈希中的每个密钥必须是唯一的。 ':category'是一个Symbol,所以你每次都覆盖最后一个值。根据你最初的尝试,它看起来并不像你对Ruby的语法有很强的把握。 – Max

+0

因此我问的问题。我需要帮助。这是SO的目的。 – narzero

+0

我明白,但它看起来太宽泛了。我不清楚你的误解在哪里,所以我想不出一个解决它的单一答案。任何体面的Ruby教程都应该涵盖这些基础知识。 – Max

回答

0

的帮助从hereherehere我有充分的工作代码:

require 'mechanize' 

@hashes = [] 

# Initialize Mechanize object 
a = Mechanize.new 

# Begin scraping 
a.get('http://www.marktplaats.nl/') do |page| 
    groups = page.search('//*[(@id = "navigation-categories")]//a') 
    groups.each_with_index do |group, index_1| 

    a.get(group[:href]) do |page_2| 
     categories = page_2.search('//*[(@id = "category-browser")]//a') 
     categories.each_with_index do |category, index_2| 

     a.get(category[:href]) do |page_3| 
      search_attributes = page_3.search('//*[contains(concat(" ", @class, " "), concat(" ", "heading", " "))]') 

      attributes_hash = {} 

      search_attributes.each_with_index do |attribute, index_3| 
      attributes_hash[index_3.to_s] = "#{attribute.text unless attribute.text == 'Outlet '}" 
      end 

      item = { 
      id: "#{index_1}.#{index_2}", 
      name: category.text, 
      group: group.text, 
      :search_attributes => attributes_hash 
      } 

      @hashes << item 

      # Uncomment this if you want to see what's being pushed 
      puts item 
     end 
     end 
    end 
    end 
end 

# Open file and begin 
File.open("json/light/#{Time.now.strftime '%Y%m%d%H%M%S'}_light_categories.json", 'w') do |f| 
    puts '# Writing category data to JSON file' 
    f.write(@hashes.to_json) 
    puts "|-----------> Done. #{@hashes.length} written." 
end 

puts '# Finished.' 
0

您是否有特殊原因使用Hash#store?这种方法没有简单的方法。我认为使用Hash#[]更好。

@categories_hash[:category] ||= {} 
@categories_hash[:category][:search_attributes] ||= {} 
@categories_hash[:category][:search_attributes][:1] = attribute.text 

||=确保您尝试存储东西在它之前的苏巴被初始化。

+0

没有特别的理由。我只是在尝试一些东西,但它不起作用。 是否有可能通过'Hash#[]'或Ruby Hashes方法来执行'Array#push'方法? – narzero

+0

我不确定你的意思。在Ruby 1.9及以上版本中,键总是按照它们添加的顺序枚举,所以'[]'足以将一个键添加到Hash的“结尾”。 – Max

+0

我已更新原始问题。使用散列#[]不会将新的键值对追加到散列的末尾。代码运行后,'@ categories_hash'只包含最后一个。有任何想法吗? – narzero

相关问题