检查 JSON var 是否有可为空的键(Twitter Streaming API)
Check if JSON var has nullable key (Twitter Streaming API)
我正在使用 Tweepy 从 Twitter Streaming API 下载推文。我设法检查下载的数据是否具有 'extended_tweet' 的密钥,但我正在努力处理另一个密钥中的特定密钥。
def on_data(self, data):
savingTweet = {}
if not "retweeted_status" in data:
dataJson = json.loads(data)
if 'extended_tweet' in dataJson:
savingTweet['text'] = dataJson['extended_tweet']['full_text']
else:
savingTweet['text'] = dataJson['text']
if 'coordinates' in dataJson:
if 'coordinates' in dataJson['coordinates']:
savingTweet['coordinates'] = dataJson['coordinates']['coordinates']
else:
savingTweet['coordinates'] = 'null'
我正在正确地检查 'extended_key',但是当我尝试对 ['coordinates]['coordinates] 做同样的事情时,我收到以下错误:
TypeError: argument of type 'NoneType' is not iterable
Twitter 文档说密钥 'coordinates' 具有以下结构:
"coordinates":
{
"coordinates":
[
-75.14310264,
40.05701649
],
"type":"Point"
}
我通过尝试将冲突检查放在一起来解决它,除了,但我认为这不是解决问题的最合适方法。还有其他想法吗?
所以 twitter API 文档可能在他们 return 的内容上撒了一些谎(令人震惊!)而且看起来你用 None
代替了预期的数据结构您已经决定不使用 try、catch,所以我不会再说了,但这里有一些其他建议。
默认使用dict get()
我想到了几个选项,第一个是利用 dict get 命令的默认功能。如果预期的密钥不存在,您可以提供回退,这允许您将多个调用链接在一起。
例如,您可以通过以下方式实现大部分您想要做的事情:
return {
'text': data.get('extended_tweet', {}).get('full_text', data['text']),
'coordinates': data.get('coordinates', {}).get('coordinates', 'null')
}
它不是很漂亮,但确实有效。您正在做的事情也可能会慢一些。
使用JSON路径
另一种选择,对于这种情况可能有点矫枉过正,是使用 JSONPath 库,它允许您在数据结构中搜索与查询匹配的项目。类似于:
from jsonpath_rw import parse
matches = parse('extended_tweet.full_text').find(data)
if matches:
print(matches[0].value)
这会比您正在做的事情慢很多,而且对于少数几个领域来说是多余的,但如果您正在做大量此类工作,它可能是一个方便的工具。 JSONPath 还可以表达更复杂的路径,或者嵌套非常深的路径,其中 get 方法可能无法工作,或者会很笨拙。
先解析JSON!
我要提到的最后一件事是确保在对 "retweeted_status"
进行测试之前解析 JSON。如果文本出现在任何地方(比如推文的文本内部),就会触发此测试。
JSON 用有能力的库解析通常也非常快,所以除非你有真正的速度问题,否则不必担心。
我正在使用 Tweepy 从 Twitter Streaming API 下载推文。我设法检查下载的数据是否具有 'extended_tweet' 的密钥,但我正在努力处理另一个密钥中的特定密钥。
def on_data(self, data):
savingTweet = {}
if not "retweeted_status" in data:
dataJson = json.loads(data)
if 'extended_tweet' in dataJson:
savingTweet['text'] = dataJson['extended_tweet']['full_text']
else:
savingTweet['text'] = dataJson['text']
if 'coordinates' in dataJson:
if 'coordinates' in dataJson['coordinates']:
savingTweet['coordinates'] = dataJson['coordinates']['coordinates']
else:
savingTweet['coordinates'] = 'null'
我正在正确地检查 'extended_key',但是当我尝试对 ['coordinates]['coordinates] 做同样的事情时,我收到以下错误:
TypeError: argument of type 'NoneType' is not iterable
Twitter 文档说密钥 'coordinates' 具有以下结构:
"coordinates":
{
"coordinates":
[
-75.14310264,
40.05701649
],
"type":"Point"
}
我通过尝试将冲突检查放在一起来解决它,除了,但我认为这不是解决问题的最合适方法。还有其他想法吗?
所以 twitter API 文档可能在他们 return 的内容上撒了一些谎(令人震惊!)而且看起来你用 None
代替了预期的数据结构您已经决定不使用 try、catch,所以我不会再说了,但这里有一些其他建议。
默认使用dict get()
我想到了几个选项,第一个是利用 dict get 命令的默认功能。如果预期的密钥不存在,您可以提供回退,这允许您将多个调用链接在一起。
例如,您可以通过以下方式实现大部分您想要做的事情:
return {
'text': data.get('extended_tweet', {}).get('full_text', data['text']),
'coordinates': data.get('coordinates', {}).get('coordinates', 'null')
}
它不是很漂亮,但确实有效。您正在做的事情也可能会慢一些。
使用JSON路径
另一种选择,对于这种情况可能有点矫枉过正,是使用 JSONPath 库,它允许您在数据结构中搜索与查询匹配的项目。类似于:
from jsonpath_rw import parse
matches = parse('extended_tweet.full_text').find(data)
if matches:
print(matches[0].value)
这会比您正在做的事情慢很多,而且对于少数几个领域来说是多余的,但如果您正在做大量此类工作,它可能是一个方便的工具。 JSONPath 还可以表达更复杂的路径,或者嵌套非常深的路径,其中 get 方法可能无法工作,或者会很笨拙。
先解析JSON!
我要提到的最后一件事是确保在对 "retweeted_status"
进行测试之前解析 JSON。如果文本出现在任何地方(比如推文的文本内部),就会触发此测试。
JSON 用有能力的库解析通常也非常快,所以除非你有真正的速度问题,否则不必担心。