Python, jsonpath: How do I parse with jsonpath cor

2019-07-30 04:48发布

问题:

I have an implementation question...

#!/usr/bin/python

#This is the API for BTC price request. 
# Average all the amounts, and push that to the program

import json
import urllib.request
from jsonpath_rw import parse as parse_jsonpath

class BtcAPI:

    def __init__(self, url, api_id, json_key):
        self.url = url
        self.api_id = api_id
        self.json_key = json_key

    def btc_api_call(self):

        hdr = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)' }
        req = urllib.request.Request(self.url, headers=hdr)
        readdata = urllib.request.urlopen(req)
        json_data = readdata.read()

        json_dict = json.loads(json_data)
        results = parse_jsonpath(self.json_key).find(json_dict)
        print(results)


class Price:


    def __init__(self, api_id, url, json_key):

        self.api_id = api_id
        self.url = url
        self.json_key = json_key

    def pass_for_request(self):

        get_price = BtcAPI(self.url, self.api_id, self.json_key)
        get_price.btc_api_call()


def Coindesk():
    coindesk = Price("coindesk","https://api.coindesk.com/v1/bpi/currentprice.json","time.updated")
coindesk.pass_for_request()

The value that gets passed for the "json_key" is "bpi.USD.rate_float"... inside this url. It gets passed to a class called "Price", which creates variables that pass to the class that the code above is contained in.

coindesk = Price("coindesk","api.coindesk.com/v1/bpi/currentprice.json", "bpi.USD.rate_float")

And here is the json I am targeting... trying to get to the rate_float key:

{
  "time": {
    "updated": "Feb 5, 2018 18:34:00 UTC",
    "updatedISO": "2018-02-05T18:34:00+00:00",
    "updateduk": "Feb 5, 2018 at 18:34 GMT"
  },
  "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org",
  "chartName": "Bitcoin",
  "bpi": {
    "USD": {
      "code": "USD",
      "symbol": "$",
      "rate": "7,004.9588",
      "description": "United States Dollar",
      "rate_float": 7004.9588
  }
}

When I run the program, it sends me the output of the entire json file, rather than the specific key I am trying to target via jsonpath, using "bpi.USD.rate_float" I'm using jsonpath_rw.

How do I target the rate_float key effectively using jsonpath?

回答1:

The problem is that you probably think results contains a plain string value from the Python dict.

That is not in fact what jsonpath_rw returns. If you look at the examples in https://github.com/kennknowles/python-jsonpath-rw you'll see it do e.g.

[match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]

And as it mentions further down:

The result of JsonPath.find provide detailed context and path data so it is easy to traverse to parent objects, print full paths to pieces of data, and generate automatic ids.

find actually returns a list of objects with contextual information. If all you want is the string value, and you only ever expect to get one return value for your JSONPath expression, you'll need to do something like:

results = parse_jsonpath(self.json_key).find(json_dict)
print(results[0].value)


回答2:

Here you go with a working Python 3 method:

def json_by_jsonpath():
    v_json     = "{\"_id\":{\"oid\":\"55561331552632234577\"},\"profilePatId\":\"123456\",\"patientPatId\":\"123456\",\"comboOrder\":false,\"globalOrderCode\":{\"$numberInt\":\"1\"},\"orderRefNum\":\"621980991862\",\"functionality\":{\"$numberInt\":\"38\"},\"rxType\":{\"$numberInt\":\"1\"},\"orderStoreNum\":\"59382\",\"orderChannel\":\"RR_EM\",\"orderChannelDtls\":\"QULL\",\"scriptDetailRetail\":[{\"rxNum\":{\"$numberInt\":\"274879\"},\"rxStoreNum\":{\"$numberInt\":\"59382\"},\"autoRefillEnabled\":false,\"autoRefillEligible\":false,\"insuranceAvailable\":false,\"sddDrugEligible\":false,\"drugQty\":{\"$numberInt\":\"0\"},\"deliveryInd\":\"1\",\"deliveryComments\":\"Ring bell and drop of in box. This comment is for SDD notes\",\"additionalComments\":\"Please call my insurance and this comment is on notes section\",\"appCode\":{\"$numberInt\":\"291\"}},{\"rxNum\":{\"$numberInt\":\"447902\"},\"rxStoreNum\":{\"$numberInt\":\"59382\"},\"autoRefillEnabled\":false,\"autoRefillEligible\":false,\"insuranceAvailable\":false,\"sddDrugEligible\":false,\"drugQty\":{\"$numberInt\":\"0\"},\"deliveryInd\":\"1\",\"deliveryComments\":\"Ring bell and drop of in box. This comment is for SDD notes\",\"additionalComments\":\"Please call my insurance and this comment is on notes section\",\"appCode\":{\"$numberInt\":\"100\"}}],\"_class\":\"com.rx.repositories.xOrderRetail\"}"


v_jsonpath =  '$._id.oid'  #'$.patientPatId'

        myjson = json.loads(v_json)
    #print(myjson)
    #result_list = [match.value for match in v_jsonpath.find(v_json)]
    #print(result_list)
    json_tag_val = parse(v_jsonpath).find(myjson)
    print(json_tag_val)

    return json_tag_val[0].value