【问题标题】:Ruby API call to get data from complex jsonRuby API 调用从复杂的 json 中获取数据
【发布时间】:2018-10-21 17:30:41
【问题描述】:

我正在使用 Ruby 进行 API GET 调用 - 调用是针对学习管理系统并返回以下 JSON:

{
    "id": 12345,
    "body": null,
    "url": null,
    "grade": "75",
    "score": 75,
    "submitted_at": "2020-05-02T11:30:53Z",
    "assignment_id": 9876,
    "user_id": 1111,
    "submission_type": "online_upload",
    "workflow_state": "graded",
    "grade_matches_current_submission": true,
    "graded_at": "2017-06-05T08:47:49Z",
    "grader_id": 2222,
    "attempt": 1,
    "cached_due_date": "2020-05-03T15:00:00Z",
    "excused": false,
    "late_policy_status": null,
    "points_deducted": null,
    "grading_period_id": null,
    "late": false,
    "missing": false,
    "seconds_late": 0,
    "entered_grade": "75",
    "entered_score": 75,
    "preview_url": "https://etcetc",
    "turnitin_data": {
        "attachment_33333": {
            "status": "scored",
            "object_id": "44444444",
            "similarity_score": 0,
            "web_overlap": 0,
            "publication_overlap": 0,
            "student_overlap": 0,
            "state": "none"
        }
    },
    "attachments": [
        {
            "id": 33333,
            "uuid": "kjsdkjhsdfkhsfd",
            "folder_id": 55555,
            "display_name": "Submission.pdf",
            "filename": "Submission.pdf",
            "content-type": "application/pdf",
            "url": "https://etcetc",
            "size": 2668226,
            "created_at": "2020-05-02T11:30:51Z",
            "updated_at": "2020-06-06T15:01:46Z",
            "unlock_at": null,
            "locked": false,
            "hidden": false,
            "lock_at": null,
            "hidden_for_user": false,
            "thumbnail_url": null,
            "modified_at": "2020-05-02T11:30:51Z",
            "mime_class": "pdf",
            "media_entry_id": null,
            "locked_for_user": false,
            "preview_url": "api/etcetc"
        }
    ],
    "submission_comments": [
        {
            "id": 99999,
            "comment": "here’s a comment",
            "author_id": 1,
            "author_name": "Mickey Mouse",
            "created_at": "2020-05-15T12:54:08Z",
            "edited_at": null,
            "avatar_path": "/images/users/1",
            "author": {
                "id": 1,
                "display_name": " Mickey Mouse ",
                "avatar_image_url": "https://etcetc",
                "html_url": "https://etcetc"
            }
        },
        {
            "id": 223344,
            "comment": "another comment",
            "author_id": 2,
            "author_name": "Donald Duck",
            "created_at": "2020-06-05T10:48:51Z",
            "edited_at": null,
            "avatar_path": "/images/users/2",
            "author": {
                "id": 2,
                "display_name": "Donald Duck",
                "avatar_image_url": "https://etcetc",
                "html_url": "https://etcetc"
            }
        }
    ]
}

我需要能够从“submission_cmets”中检索特定值,即“comment”、“author_id”和“author_name”的值。目前我能做的最好的就是将“submission_cmets”作为一个大实体来检索。这是我如何做到这一点的:

require 'typhoeus'
require 'link_header'
require 'json'
require 'csv'

the_url = 'https://etctetc' 
token = 'mytoken'
api_endpoint = '/api/etc'
output_csv = 'C:\Users\me\Desktop\Ruby Canvas course\assignment_comments.csv'

CSV.open(output_csv, 'wb') do |csv|
    csv << ["user_id", "TII", "marker"]
end

request_url = "#{the_url}#{api_endpoint}"
count = 0
more_data = true
while more_data  
    get_comments = Typhoeus::Request.new(
        request_url,    
        method: :get,
        headers: { authorization: "Bearer #{token}" }
        )

        get_comments.on_complete do |response|
        #get next link
            links = LinkHeader.parse(response.headers['link']).links
            next_link = links.find { |link| link['rel'] == 'next' } 
            request_url = next_link.href if next_link 
            if next_link && "#{response.body}" != "[]"
                more_data = true
            else
                more_data = false
            end

        if response.code == 200
            data = JSON.parse(response.body)
            data.each do |comments|
                CSV.open(output_csv, 'a') do |csv|
                    csv << [comments['id'], comments['turnitin_data'], comments['submission_comments']]
                end
            end
        else
            puts "Something went wrong! Response code was #{response.code}"
        end
    end

    get_comments.run
end
puts "Script done running"

我是新手(ruby 代码基于练习,所以我可能无法完全理解)- 任何帮助/建议将不胜感激!

编辑:我还应该注意,这不是我正在处理的全部 JSON 响应 - 这只是返回的十个项目之一

【问题讨论】:

  • 只是想添加一个道歉,我确实试图让 JSON 以上面“漂亮”的形式呈现,但这似乎没有用:(
  • 您唯一缺少的是将每行缩进 4 个空格(选择块并按 cmd+k)。 FTFY。
  • 那么你的问题是关于如何在 ruby​​ 中从 JSON 中检索一个值?也许您可以删除 API 调用酱,这对您的主题来说似乎是不必要的。

标签: json ruby rest


【解决方案1】:
"submission_comments": [
        {
            "id": 99999,
        }
]

[] 表示它是数组。 {} 表示它是一个对象。

所以你可能需要做这样的事情:

json["submission_comments"].first["id"]

或更好地遍历它:

ids = json["submission_comments"].map{|comment| comment["id"]}

【讨论】:

    【解决方案2】:

    如果您可以将 JSON 文件作为文本读取,然后使用 Ruby 的 JSON.parse(...) 方法,我可以获得您需要的变量。我认为主要问题是 JSON 使用 null 而 Ruby 哈希使用 nil。您可以进行字符串替换或尝试类似的操作(我没有修改您的 JSON,仅将其放入单引号字符串中):

    json_text = '{
        "id": 12345,
        "body": null,
        "url": null,
        "grade": "75",
        "score": 75,
        "submitted_at": "2020-05-02T11:30:53Z",
        "assignment_id": 9876,
        "user_id": 1111,
        "submission_type": "online_upload",
        "workflow_state": "graded",
        "grade_matches_current_submission": true,
        "graded_at": "2017-06-05T08:47:49Z",
        "grader_id": 2222,
        "attempt": 1,
        "cached_due_date": "2020-05-03T15:00:00Z",
        "excused": false,
        "late_policy_status": null,
        "points_deducted": null,
        "grading_period_id": null,
        "late": false,
        "missing": false,
        "seconds_late": 0,
        "entered_grade": "75",
        "entered_score": 75,
        "preview_url": "https://etcetc",
        "turnitin_data": {
            "attachment_33333": {
                "status": "scored",
                "object_id": "44444444",
                "similarity_score": 0,
                "web_overlap": 0,
                "publication_overlap": 0,
                "student_overlap": 0,
                "state": "none"
            }
        },
        "attachments": [
            {
                "id": 33333,
                "uuid": "kjsdkjhsdfkhsfd",
                "folder_id": 55555,
                "display_name": "Submission.pdf",
                "filename": "Submission.pdf",
                "content-type": "application/pdf",
                "url": "https://etcetc",
                "size": 2668226,
                "created_at": "2020-05-02T11:30:51Z",
                "updated_at": "2020-06-06T15:01:46Z",
                "unlock_at": null,
                "locked": false,
                "hidden": false,
                "lock_at": null,
                "hidden_for_user": false,
                "thumbnail_url": null,
                "modified_at": "2020-05-02T11:30:51Z",
                "mime_class": "pdf",
                "media_entry_id": null,
                "locked_for_user": false,
                "preview_url": "api/etcetc"
            }
        ],
        "submission_comments": [
            {
                "id": 99999,
                "comment": "here’s a comment",
                "author_id": 1,
                "author_name": "Mickey Mouse",
                "created_at": "2020-05-15T12:54:08Z",
                "edited_at": null,
                "avatar_path": "/images/users/1",
                "author": {
                    "id": 1,
                    "display_name": " Mickey Mouse ",
                    "avatar_image_url": "https://etcetc",
                    "html_url": "https://etcetc"
                }
            },
            {
                "id": 223344,
                "comment": "another comment",
                "author_id": 2,
                "author_name": "Donald Duck",
                "created_at": "2020-06-05T10:48:51Z",
                "edited_at": null,
                "avatar_path": "/images/users/2",
                "author": {
                    "id": 2,
                    "display_name": "Donald Duck",
                    "avatar_image_url": "https://etcetc",
                    "html_url": "https://etcetc"
                }
            }
        ]
    }'
    

    我补充的部分:

      ruby_hash = JSON.parse(json_text)
      submission_comments = ruby_hash["submission_comments"]
      submission_comments.each do |submission_comment|
        comment = submission_comment["comment"]
        author_id = submission_comment["author_id"]
        author_name = submission_comment["author_name"]
        puts "Comment: #{comment}, Author ID: #{author_id}, Author Name: #{author_name}\n\n"
      end
    

    最终结果:

    => 评论:这是一条评论,作者 ID:1,作者姓名:米老鼠

    => 评论:另一条评论,作者 ID:2,作者姓名:唐老鸭


    编辑:我添加了一个 jenky af 单线版本只是为了好玩(假设上面的 json_text 变量已经初始化)

    JSON.parse(json_text)["submission_comments"]
        .map{|txt| puts(["comment","author_id","author_name"]
            .map{|k| k.instance_eval{"#{upcase}: #{txt[to_s]}"}}.join(', '))}
    

    COMMENT:这是一条评论,AUTHOR_ID: 1, AUTHOR_NAME: Mickey Mouse

    COMMENT:另一条评论,AUTHOR_ID:2,AUTHOR_NAME:唐老鸭

    【讨论】:

    • 您好 oMiKeY,谢谢您 - 如果我像您一样在开头/结尾手动添加单引号,我可以运行这两个版本。不过,我需要让脚本处理添加这些内容,但这次尝试失败了: json2 = "'#{json_text}'" puts json2
    • 我认为这确实应该工作......但总是有:json2 = "'" + json_text + "'"(如果我正确理解你的情况)
    猜你喜欢
    • 2019-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-15
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多