【问题标题】:Rake Task to parse JSON, some objects might be missing用于解析 JSON 的 Rake 任务,可能缺少某些对象
【发布时间】:2018-01-01 02:26:15
【问题描述】:

我制作了一个简单的 Rake 任务来解析一些 JSON,并使用它来将一些属性应用于游戏集合。

为避免此块中出现大量 JSON 列表,可以预览 JSON herehere - 这些来自 Steam 商店的 API 返回游戏详细信息。当我只提取每条记录上存在的两条信息时,我的 rake 起作用了(假设它是成功的)

desc 'update steam game info'

namespace :update_steam_games do

    task scrape_info: :environment do
     require 'open-uri'
    #require 'nokogiri'
    require 'json'

    games = SteamGame.first(10)
    games.each do |game|
        base_url = "http://store.steampowered.com/api/appdetails?appids=#{game['appid']}"
        puts "base_url: #{base_url}"
        results = open(base_url) { |f|
            result = JSON.parse(f.read)
            puts result.inspect
            next if result[game['appid'].to_s]['success'] == false
            type = result[game['appid'].to_s]['data']['type']
            detailed_description = result[game['appid'].to_s]['data']['detailed_description']
            about_the_game = result[game['appid'].to_s]['data']['about_the_game']
            short_description = result[game['appid'].to_s]['data']['short_description']
            supported_languages = result[game['appid'].to_s]['data']['supported_languages']
            if !result[game['appid'].to_s]['data']['dlc'].nil?
                dlc = result[game['appid'].to_s]['data']['dlc'].flatten
            end
            is_free = result[game['appid'].to_s]['data']['is_free']
            required_age = result[game['appid'].to_s]['data']['required_age']
            genres = result[game['appid'].to_s]['data']['genres'].map { |g| g['description'] }
            developers = result[game['appid'].to_s]['data']['developers']
            publishers = result[game['appid'].to_s]['data']['publishers']
            windows = result[game['appid'].to_s]['data']['platforms']['windows']
            mac = result[game['appid'].to_s]['data']['platforms']['mac']
            metacritic_score = result[game['appid'].to_s]['data']['metacritic']['score']
            metacritic_link = result[game['appid'].to_s]['data']['metacritic']['url']
            #game.update_attributes(genres: genres, detailed_description: detailed_description)

            puts game.inspect
        }
        end
    end
end

我得到的当前错误是 NoMethodError: undefined method[]' for nil:NilClass` on line 34 - 这也是属性分配的结束,所以我不确定它是否与该行直接相关。

我确实意识到我试图将布尔值存储为整数并已修复它,但现在出现此错误。

我尝试将所有内容包装到 if XXX .present? 包装器中,但随后得到如下

desc 'update steam game info'

namespace :update_steam_games do

    task scrape_info: :environment do
     require 'open-uri'
    #require 'nokogiri'
    require 'json'

    games = SteamGame.first(10)
    games.each do |game|
        base_url = "http://store.steampowered.com/api/appdetails?appids=#{game['appid']}"
        puts "base_url: #{base_url}"
        results = open(base_url) { |f|
            result = JSON.parse(f.read)
            puts result.inspect
            next if result[game['appid'].to_s]['success'] == false
            if type = result[game['appid'].to_s]['data']['type'].present?
                type = result[game['appid'].to_s]['data']['type']
            end
            if detailed_description = result[game['appid'].to_s]['data']['detailed_description'].present?
                detailed_description = result[game['appid'].to_s]['data']['detailed_description']
            end
            if about_the_game = result[game['appid'].to_s]['data']['about_the_game'].present?
                about_the_game = result[game['appid'].to_s]['data']['about_the_game']
            end
            if short_description = result[game['appid'].to_s]['data']['short_description'].present?
                short_description = result[game['appid'].to_s]['data']['short_description']
            end
            if supported_languages = result[game['appid'].to_s]['data']['supported_languages'].present?
                supported_languages = result[game['appid'].to_s]['data']['supported_languages']
            end
            if result[game['appid'].to_s]['data']['dlc'].present?.present?
                    dlc = result[game['appid'].to_s]['data']['dlc'].flatten
            end
            if is_free = result[game['appid'].to_s]['data']['is_free'].present?
                is_free = result[game['appid'].to_s]['data']['is_free']
            end
            if required_age = result[game['appid'].to_s]['data']['required_age'].present?
                required_age = result[game['appid'].to_s]['data']['required_age']
            end
            if genres = result[game['appid'].to_s]['data']['genres'].map { |g| g['description'] }.present?
                genres = result[game['appid'].to_s]['data']['genres'].map { |g| g['description'] }
            end
            if developers = result[game['appid'].to_s]['data']['developers'].present?
                developers = result[game['appid'].to_s]['data']['developers']
            end
            if publishers = result[game['appid'].to_s]['data']['publishers'].present?
                publishers = result[game['appid'].to_s]['data']['publishers']
            end
            if windows = result[game['appid'].to_s]['data']['platforms']['windows'].present?
                windows = result[game['appid'].to_s]['data']['platforms']['windows']
            end
            if mac = result[game['appid'].to_s]['data']['platforms']['mac'].present?
                mac = result[game['appid'].to_s]['data']['platforms']['mac']
            end
            if metacritic_score = result[game['appid'].to_s]['data']['metacritic']['score'].present?
                metacritic_score = result[game['appid'].to_s]['data']['metacritic']['score']
            end
            if metacritic_link = result[game['appid'].to_s]['data']['metacritic']['url'].present?
                metacritic_link = result[game['appid'].to_s]['data']['metacritic']['url']
            end
            #game.update_attributes(genres: genres, detailed_description: detailed_description)

            puts game.inspect
        }
        end
    end
end

但实际上我仍然遇到了同样的问题,除了我不确定如何将它传递给 game.update_attributes 甚至不知道它是否存在。

我如何检查真正的问题,并减少冗余?

JSON

如果您不想点击我在此处提供的 JSON 示例的链接。我已经删除了一些膨胀。它开头的10 是动态ID。

  "10": {
    "success": true,
    "data": {
      "type": "game",
      "name": "Counter-Strike",
      "steam_appid": 10,
      "required_age": 0,
      "is_free": false,
      "detailed_description": "Play the world's number 1 online action game. Engage in an incredibly realistic brand of terrorist warfare in this wildly popular team-based game. Ally with teammates to complete strategic missions. Take out enemy sites. Rescue hostages. Your role affects your team's success. Your team's success affects your role.",
      "about_the_game": "Play the world's number 1 online action game. Engage in an incredibly realistic brand of terrorist warfare in this wildly popular team-based game. Ally with teammates to complete strategic missions. Take out enemy sites. Rescue hostages. Your role affects your team's success. Your team's success affects your role.",
      "short_description": "",
      "supported_languages": "English, French, German, Italian, Spanish, Simplified Chinese, Traditional Chinese, Korean",
      "header_image": "http://cdn.akamai.steamstatic.com/steam/apps/10/header.jpg?t=1447887426",
      "website": null,
      "pc_requirements": {
        "minimum": "\n\t\t\t<p><strong>Minimum:</strong> 500 mhz processor, 96mb ram, 16mb video card, Windows XP, Mouse, Keyboard, Internet Connection<br /></p>\n\t\t\t<p><strong>Recommended:</strong> 800 mhz processor, 128mb ram, 32mb+ video card, Windows XP, Mouse, Keyboard, Internet Connection<br /></p>\n\t\t\t"
      },
      "mac_requirements": {
        "minimum": "Minimum: OS X  Snow Leopard 10.6.3, 1GB RAM, 4GB Hard Drive Space,NVIDIA GeForce 8 or higher, ATI X1600 or higher, or Intel HD 3000 or higher Mouse, Keyboard, Internet Connection"
      },
      "linux_requirements": {
        "minimum": "Minimum: Linux Ubuntu 12.04, Dual-core from Intel or AMD at 2.8 GHz, 1GB Memory, nVidia GeForce 8600/9600GT, ATI/AMD Radeaon HD2600/3600 (Graphic Drivers: nVidia 310, AMD 12.11), OpenGL 2.1, 4GB Hard Drive Space, OpenAL Compatible Sound Card"
      },
      "developers": [
        "Valve"
      ],
      "publishers": [
        "Valve"
      ],
      "price_overview": {
        "currency": "USD",
        "initial": 999,
        "final": 999,
        "discount_percent": 0
      },
      "packages": [
        7
      ],
      "package_groups": [
        {
          "name": "default",
          "title": "Buy Counter-Strike",
          "description": "",
          "selection_text": "Select a purchase option",
          "save_text": "",
          "display_type": 0,
          "is_recurring_subscription": "false",
          "subs": [
            {
              "packageid": 7,
              "percent_savings_text": "",
              "percent_savings": 0,
              "option_text": "Counter-Strike: Condition Zero - $9.99",
              "option_description": "",
              "can_get_free_license": "0",
              "is_free_license": false,
              "price_in_cents_with_discount": 999
            }
          ]
        }
      ],
      "platforms": {
        "windows": true,
        "mac": true,
        "linux": true
      },
      "metacritic": {
        "score": 88,
        "url": "http://www.metacritic.com/game/pc/counter-strike?ftag=MCD-06-10aaa1f"
      }
    }
}

更新

我意识到如果platform 不存在,我无法检查platform - windows 的存在。代码现在成功执行,但是,我在编写时遇到了问题,因为很多参数可能会或可能不会在每次传递时丢失。

什么是正确的方法来代替if 到处都是块?

更新

在我意识到我愚蠢地将if 块放在变量定义部分周围之后,我的代码现在可以工作了。

但是,这仍然是多余的。有没有合适的方法来做到这一点,或者这样可以吗?

【问题讨论】:

标签: ruby-on-rails json ruby


【解决方案1】:
games = SteamGame.first(10)
games.each do |game|
    base_url = "http://store.steampowered.com/api/appdetails?appids=#{game['appid']}"
    puts "base_url: #{base_url}"
    results = open(base_url) { |f|
        result = JSON.parse(f.read)
        game_appid = game[:appid].to_s
        result_for_appid = result[game_appid]
        result_data = result_for_appid[:data]
        puts result.inspect
        next if result_for_appid[:success] == false
        type = result_data[:type]
        detailed_description = result_data[:detailed_description]
        about_the_game = result_data[:about_the_game]
        short_description = result_data[:short_description]
        supported_languages = result_data[:supported_languages]
        if result_data[:dlc].present?
            dlc = result_data[:dlc].flatten
        end
        is_free = result_data[:is_free]
        required_age = result_data[:required_age]
        # genres = result_data[:genres].map { |g| g[:description] }
        # Your provided JSON didn't contain 'genres' inside 'data'
        developers = result_data[:developers]
        publishers = result_data[:publishers]
        windows = result_data[:platforms][:windows]
        mac = result_data[:platforms][:mac]
        metacritic_score = result_data[:metacritic][:score]
        metacritic_link = result_data[:metacritic][:url]
        # game.update_attributes(genres: genres, detailed_description: detailed_description)
        # Your provided JSON didn't contain 'genres' inside 'data' so no update for this
        game.update_attributes(detailed_description: detailed_description)

        puts game.inspect
    }
    end
end

对此的一些提示: DRY - 不要重复自己 您可以将 json 键作为符号访问 您提供的 JSON 中没有“流派” 您不必使用 IF - 当没有数据时您将得到:variable = nil。您可以稍后更新有关变量值的属性。

【讨论】:

  • 谢谢 - 是的,类型的东西实际上是我对成功的问题的一部分。我的问题是现在当它到达任何空白的列时,我得到的响应类似于 `NoMethodError: undefined method[]' for nil:NilClass`` - 我将尝试使用您的预定义数据逻辑因为我讨厌到处都是 if 块。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 2016-06-09
  • 2013-08-06
  • 1970-01-01
  • 2017-03-01
  • 2016-12-15
  • 2011-04-26
相关资源
最近更新 更多