Chuyển đổi JSON lồng nhau sang đối tượng Python

Tôi được yêu cầu giúp phân tích cú pháp một tệp JSON được phân phối bởi điểm cuối JSON của API Đánh giá của khách hàng trên iTunes Store. Việc API này hoạt động như thế nào hoặc liệu có API nào tốt hơn cho việc này không quá quan trọng. Thay vào đó, hãy giả sử rằng chúng tôi đã tìm thấy API yêu thích của mình để hoạt động và yêu cầu của chúng tôi hoàn toàn hợp lý và bây giờ chúng tôi phải xử lý phản hồi của API, JSON trong trường hợp này. Bài viết này sẽ hướng dẫn bạn các bước cần thiết để phân tích cú pháp phản hồi JSON này thành một chú gấu trúc

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
3. Tôi sẽ tập trung nhiều vào các khái niệm và phát triển mã và ít hơn vào việc giải thích từng dòng mã. Tốt nhất, bạn nên làm quen với ít nhất một chút Python và các kiểu dữ liệu tiêu chuẩn của nó, quan trọng nhất là từ điển

Đầu tiên, tôi muốn hiểu những gì tôi đang giải quyết và vì việc hiển thị phản hồi JSON không đẹp lắm đối với URL ban đầu, nên tôi sử dụng công cụ xác thực JSON như http. //json làm đẹp. com/

Điều này sẽ cung cấp cho tôi phản hồi JSON được định dạng lại sau đây

{
    "feed": {
        "author": {
            "name": {
                "label": "iTunes Store"
            },
            "uri": {
                "label": "//www.apple.com/uk/itunes/"
            }
        },
        "entry": [
            {
                "author": {
                    "uri": {
                        "label": "//itunes.apple.com/gb/reviews/id1413855597"
                    },
                    "name": {
                        "label": "VedantJM"
                    },
                    "label": ""
                },
                "updated": {
                    "label": "2022-05-31T14:20:49-07:00"
                },
                "im:rating": {
                    "label": "5"
                },
                "im:version": {
                    "label": "2.38"
                },
                "id": {
                    "label": "8727815893"
                },
                "title": {
                    "label": "Brilliant"
                },
                "content": {
                    "label": "Adonissss",
                    "attributes": {
                        "type": "text"
                    }
                },
                "link": {
                    "attributes": {
                        "rel": "related",
                        "href": "//itunes.apple.com/gb/review?id=1500780518&type=Purple%20Software"
                    }
                },
                "im:voteSum": {
                    "label": "0"
                },
                "im:contentType": {
                    "attributes": {
                        "term": "Application",
                        "label": "Application"
                    }
                },
                "im:voteCount": {
                    "label": "0"
                }
            },
            ...

Tôi chỉ hiển thị đối tượng

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
4 đầu tiên của danh sách
import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
5. Vì vậy, phản hồi JSON được cấu trúc theo cách sau

  • chúng tôi có một phần tử gốc duy nhất "nguồn cấp dữ liệu"
  • phần tử gốc này chỉ có hai phần tử con, “tác giả” và “mục nhập”, từ đó tôi chỉ quan tâm đến “mục nhập”
  • “entry” là một danh sách các đối tượng và mỗi đối tượng có một tập hợp các thuộc tính như “tác giả”, “liên kết” và “im. Xếp hạng"
  • Mỗi thuộc tính lại là một đối tượng JSON
  • Thuộc tính đơn giản nhất là một đối tượng chỉ có khóa “nhãn” và giá trị
  • Các thuộc tính phức tạp hơn như “tác giả” lại được lồng vào nhau

Trước khi tôi tìm hiểu sâu hơn về cách phân tích cú pháp cấu trúc lồng nhau này, hãy để tôi thử phương pháp

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
6 của pandas trước

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]

Đầu ra của cái này là bảng sau

tác giả nguồn cấp dữ liệu {'tên'. {'nhãn'. ‘Cửa hàng iTunes’}, ‘uri’. {'l...mục [{'tác giả'. {'uri'. {'nhãn'. ‘https. // itunes…. biểu tượng{'nhãn'. ‘http. // itunes. táo. com/favicon. ico'}id{'nhãn'. ‘https. //mzstoreservices-int-st. itun…link[{'thuộc tính'. {'rel'. 'thay thế', 'loại'. '...quyền{'nhãn'. ‘Bản quyền 2008 Apple Inc. ’}tiêu đề{‘nhãn’. Cửa hàng iTunes. Đánh giá của khách hàng'}đã cập nhật{'nhãn'. ‘2022-06-02T11. 44. 53-07. 00’}

Đây rõ ràng không phải là những gì tôi đã có trong tâm trí. Vấn đề đầu tiên tôi nên loại bỏ là gấu trúc không thể biết rằng tôi chỉ quan tâm đến danh sách “mục nhập”, vì vậy trước tiên tôi sẽ tìm nạp phản hồi JSON, phân tích nó thành từ điển và truy cập giá trị “mục nhập”

import requests

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"

r = requests.get[url]

data = r.json[]
entries = data["feed"]["entry"]

Do đó,

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
7 trông như thế này

________số 8_______

Bây giờ, tôi có thể thử gấu trúc một lần nữa. Lưu ý rằng tôi không còn chuỗi JSON nữa mà là danh sách Python bình thường, chứa từ điển. Do đó, tôi có thể trực tiếp sử dụng pandas

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
3class

df = pd.DataFrame[entries]

Các hàng đầu tiên của khung dữ liệu này trông như sau [

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
9]

tác giảupdatedim. đánh giá. versionidtitlecontentlinkim. bình chọnSumim. nội dungTypeim. voteCount0{'uri'. {'nhãn'. ‘https. // itunes. táo. com/gb…{'nhãn'. ‘2022-06-01T08. 25. 00-07. 00’}{‘nhãn’. '5'}{'nhãn'. ‘2. 38’}{‘nhãn’. '8730361700'}{'nhãn'. 'Ứng dụng tuyệt vời'}{'nhãn'. 'Ứng dụng thiền này là trên hết, tôi...{'thuộc tính'. {'rel'. 'liên quan', 'href'. 'htt...{'nhãn'. ‘0’}{‘thuộc tính’. {'thuật ngữ'. 'Ứng dụng', 'nhãn'...{'nhãn'. ‘0’}1{‘uri’. {'nhãn'. ‘https. // itunes. táo. com/gb…{'nhãn'. ‘2022-05-31T14. 20. 49-07. 00’}{‘nhãn’. '5'}{'nhãn'. ‘2. 38’}{‘nhãn’. '8727815893'}{'nhãn'. ‘Rực rỡ’}{‘nhãn’. 'Adonissss', 'thuộc tính'. {'loại'. …{'thuộc tính'. {'rel'. 'liên quan', 'href'. 'htt...{'nhãn'. ‘0’}{‘thuộc tính’. {'thuật ngữ'. 'Ứng dụng', 'nhãn'...{'nhãn'. ‘0’}2{‘uri’. {'nhãn'. ‘https. // itunes. táo. com/gb…{'nhãn'. ‘2022-05-31T08. 25. 36-07. 00’}{‘nhãn’. '5'}{'nhãn'. ‘2. 38’}{‘nhãn’. '8726950116'}{'nhãn'. ‘Hoàn hảo’}{‘nhãn’. 'Ứng dụng này là ứng dụng dành cho thiền định...{'thuộc tính'. {'rel'. 'liên quan', 'href'. 'htt...{'nhãn'. ‘0’}{‘thuộc tính’. {'thuật ngữ'. 'Ứng dụng', 'nhãn'...{'nhãn'. '0'}

Tốt hơn nhiều nhưng vẫn chưa có. Chúng tôi có các cột chính xác và mỗi hàng thực sự là một mục từ danh sách mục nhập. Tuy nhiên, tất cả các giá trị đều là chuỗi và tệ hơn là biểu diễn chuỗi của các từ điển bên trong [và đôi khi là nhiều từ điển lồng nhau]. Tôi không thể làm việc với dữ liệu như thế này vì vậy chúng tôi phải phân tích cú pháp thủ công danh sách các mục, tôi sẽ giải thích điều này tiếp theo

Nhìn lại cấu trúc của các mục nhập [xem Liệt kê “phản hồi JSON”], chiến lược rất đơn giản. đi qua từng mục nhập và miễn là giá trị là một từ điển, hãy nối các khóa thành một tên cột duy nhất và giá trị cuối cùng là giá trị cho cột và hàng này

Bây giờ, một nỗ lực đầu tiên rất thô sơ có thể là mã hóa cứng tất cả các tên thuộc tính như thế này

parsed_data = defaultdict[list]

for entry in entries:
    parsed_data["author_uri"].append[entry["author"]["uri"]["label"]]
    parsed_data["author_name"].append[entry["author"]["name"]["label"]]
    parsed_data["author_label"].append[entry["author"]["label"]]
    parsed_data["content_label"].append[entry["content"]["label"]]
    parsed_data["content_attributes_type"].append[entry["content"]["attributes"]["type"]]
    .. 
                    

Việc triển khai này có thể ngây thơ và hoàn toàn không khái quát hóa cho bất kỳ trường hợp sử dụng nào khác, nhưng đây vẫn là một phương pháp hiệu quả cao để bắt đầu vì nó buộc bạn phải nêu rõ ràng cấu trúc JSON xuống phần tử cuối cùng. Phương pháp này hoạt động có thể được kiểm tra lại với lớp gấu trúc

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
3 có thể tạo khung dữ liệu từ một từ điển có danh sách các giá trị cho mỗi cột

pd.DataFrame[parsed_data]

Đầu ra sẽ là một khung dữ liệu như thế này

author_uriauthor_nameauthor_labelcontent_labelcontent_attributes_type0https. // itunes. táo. com/gb/reviews/id1351156521hdydgdbsỨng dụng thiền này là trên hết, nó hoạt động và…text1https. // itunes. táo. com/gb/reviews/id1413855597VedantJMAdonisssstext2https. // itunes. táo. com/gb/reviews/id1413779831dtnvcgiifgh Ứng dụng này dành cho thiền định, văn bản tự…tuyệt vời

Tuy nhiên, nhằm vào một giải pháp tổng quát hơn có thể tự động xử lý tất cả các thuộc tính/thuộc tính mà không cần biết cấu trúc [nhưng dựa trên thực tế là chỉ có hai cấp từ điển lồng nhau, ít nhất là cho đến bây giờ], tôi đã rút ra giải pháp sau

parsed_data = defaultdict[list]

for entry in entries:
    for key, val in entry.items[]:
        for subkey, subval in val.items[]:
            if not isinstance[subval, dict]:
                parsed_data[f"{key}_{subkey}"].append[subval]
            else:
                for att_key, att_val in subval.items[]:
                    parsed_data[f"{key}_{subkey}_{att_key}"].append[att_val]

Mã không phải là mã đẹp nhất nhưng tôi sẽ đến phần này sau. Bây giờ hãy tập trung vào ý định. Đối với mỗi mục nhập, tôi xem xét cặp khóa-giá trị đầu tiên, biết rằng giá trị đó luôn là một từ điển [đối tượng trong JSON]. Bây giờ tôi phải đối phó với hai trường hợp khác nhau. Trong trường hợp đầu tiên, từ điển giá trị phẳng và không chứa từ điển khác, chỉ chứa các cặp khóa-giá trị. Đây là trường hợp đơn giản mà tôi kết hợp khóa bên ngoài với khóa bên trong thành tên cột và lấy giá trị làm giá trị cột cho mỗi cặp. Trong trường hợp thứ hai, từ điển chứa cặp khóa-giá trị trong đó giá trị lại là từ điển. Tôi dựa vào thực tế là có nhiều nhất hai cấp từ điển lồng nhau nên tôi lặp lại các cặp khóa-giá trị của từ điển bên trong và kết hợp lại khóa bên ngoài và khóa bên trong nhất thành tên cột và lấy giá trị bên trong làm cột

Quy trình này cung cấp cho tôi một từ điển trong đó các khóa là tên cột của khung dữ liệu và mỗi khóa có một danh sách dưới dạng giá trị với các giá trị hàng cho cột này. Đây là định dạng hoàn hảo cho lớp DataFrame của gấu trúc để tạo khung dữ liệu từ

df = pd.DataFrame[parsed_data]
df.head[]

Và các hàng đầu tiên trông như thế này

author_uri_labelauthor_name_labelauthor_labelupdated_labelim. rating_labelim. version_labelid_labeltitle_labelcontent_labelcontent_attributes_typelink_attributes_rellink_attributes_hrefim. bình chọnSum_labelim. contentType_attributes_termim. contentType_attributes_labelim. bình chọnCount_label0https. // itunes. táo. com/gb/đánh giá/id1351156521hdydgdbs2022-06-01T08. 25. 00-07. 0052. 388730361700Ứng dụng tuyệt vờiỨng dụng thiền này là trên hết, nó hoạt động và…liên quan đến văn bảnhttps. // itunes. táo. com/gb/review?id=15007805…0ApplicationApplication01https. // itunes. táo. com/gb/đánh giá/id1413855597VedantJM2022-05-31T14. 20. 49-07. 0052. 388727815893Rực rỡAdonisssstextliên quanhttps. // itunes. táo. com/gb/review?id=15007805…0ApplicationApplication02https. // itunes. táo. com/gb/đánh giá/id1413779831dtnvcgiifgh2022-05-31T08. 25. 36-07. 0052. 388726950116Hoàn hảoỨng dụng này là ứng dụng dành cho thiền định, rất tuyệt…liên quan đến văn bảnhttps. // itunes. táo. com/gb/review?id=15007805…0ApplicationApplication0

Và nó đây rồi. Tôi có nhiều cột hơn dự kiến ​​ban đầu vì tôi quyết định giữ lại mọi bit thông tin bằng cách làm phẳng cấu trúc lồng nhau của các ký tự thành một ký tự duy nhất trong đó mỗi tổ hợp thuộc tính được giữ nguyên bằng cách nối các khóa khác nhau thành một tên cột duy nhất, được phân tách bằng dấu . Khung dữ liệu này có 50 hàng và 16 cột, phù hợp với phản hồi JSON ban đầu. Nếu bạn không thích phần “nhãn” bổ sung trong tên cột, bạn có thể dễ dàng loại bỏ nó

df.columns = [col if not "label" in col else "_".join[col.split["_"][:-1]] for col in df.columns]

Ngay bây giờ, tất cả các cột đều có kiểu dữ liệu

import requests

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"

r = requests.get[url]

data = r.json[]
entries = data["feed"]["entry"]
1, đây không phải là bộ nhớ lý tưởng, nhưng không có tác động lớn miễn là tập dữ liệu nhỏ như thế này. Tuy nhiên, tôi có thể thay đổi dtype bằng một lớp lót đơn giản

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
0

Pandas

import requests

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"

r = requests.get[url]

data = r.json[]
entries = data["feed"]["entry"]
2 phương pháp xác nhận dàn diễn viên

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
1

Để kết thúc bài viết này, tôi muốn cải thiện khả năng sử dụng lại mã của mình. Điều hiển nhiên đầu tiên cần làm là trích xuất logic phân tích cú pháp thành một hoặc một số hàm với chú thích loại và chuỗi tài liệu phù hợp. Tuy nhiên, đây không phải là trọng tâm của bài viết này nên tôi sẽ dành phần này cho người đọc có khuynh hướng thực tế hơn

Thay vào đó, tôi muốn nhấn mạnh rằng giải pháp của tôi [Liệt kê “triển khai nâng cao”] phá vỡ các cấu trúc JSON lồng nhau sâu hơn. Đó là bởi vì tôi phải lặp lại một cách rõ ràng các từ điển bên trong với một vòng lặp

import requests

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"

r = requests.get[url]

data = r.json[]
entries = data["feed"]["entry"]
3 cho mỗi từ điển. Một giải pháp tốt hơn cho vấn đề như vậy là một cách tiếp cận đệ quy trong đó chúng tôi áp dụng mô hình chia để trị để xử lý sự phức tạp. Nói cách khác, điều tôi thực sự định làm là đi vào từng từ điển miễn là có các từ điển bên trong và khi tôi đến cuối, hãy thêm tất cả các giá trị dưới dạng các cột riêng biệt

import pandas as pd

url = "//itunes.apple.com/gb/rss/customerreviews/id=1500780518/sortBy=mostRecent/json"
pd.read_json[url]
2

đó không phải là một vẻ đẹp. Giống như thường lệ khi cách tiếp cận đệ quy tự nhiên hơn đối với nhiệm vụ hiện tại, việc triển khai đệ quy dễ đọc hơn và thường ngắn hơn cách tiếp cận lặp. Bạn có thể tự xác minh rằng khung dữ liệu thu được theo phương pháp này giống hệt với khung dữ liệu thu được từ giải pháp lặp trước đó

Tất nhiên có những cách tiếp cận khác. Một chiến lược phổ biến là làm phẳng JSON gốc bằng cách thực hiện điều gì đó rất giống như chúng tôi đã làm ở đây. rút ra tất cả các đối tượng lồng nhau bằng cách nối tất cả các khóa và giữ giá trị bên trong cuối cùng. Nếu bạn thay đổi JSON ban đầu như thế này, bạn sẽ nhận được một JSON có thể được đưa trực tiếp vào gấu trúc. Thậm chí còn có một mô-đun bạn có thể sử dụng ngay lập tức. làm phẳng_json. Nhưng đâu sẽ là niềm vui trong việc này…

Tôi hy vọng bạn thích theo dõi tôi trong cuộc hành trình nhỏ này và như mọi khi, tôi sẵn sàng đón nhận các nhận xét, thảo luận và câu hỏi của bạn

Chủ Đề