如何优雅地解决 Python KeyError(Python csv 库)
How to resolve Python KeyError elegantly (Python csv library)
我在 Python 中使用 lxml 和 JSON 库编写了一个基本的网络抓取工具。下面的代码片段详细说明了我目前如何写入 CSV:
with open(filepath, "ab") as f:
write = csv.writer(f)
try:
write.writerow(["allhomes",
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr,
'', # fill this in! should be 'description'
node["state"],
node["suburb"],
node["postcode"],
node["propertyType"],
node["bathrooms"],
node["bedrooms"],
node["parking"],
pricenode,
node["photoCount"],
node2["pricemin"],
node2["pricemax"],
node2["pricerange"]])
except KeyError, e:
try:
write.writerow(["allhomes",
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr,
'', # fill this in! should be 'description'
node["state"],
node["suburb"],
node["postcode"],
node["propertyType"],
'',
node["bedrooms"],
node["parking"],
pricenode,
node["photoCount"],
node2["pricemin"],
node2["pricemax"],
node2["pricerange"]])
except KeyError, e:
errorcount += 1
with open(filepath, "ab"): #
write = csv.writer(f)
write.writerow(["Error: invalid dictionary field key: %s" % e.args,
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr])
pass
pass
问题在于,如果某个节点不存在(最常见的是 Bathrooms 节点),我必须通过将 Bathrooms 节点替换为空值来重试,或者随后放弃整行数据。我目前的方法是重试并通过删除 Bathrooms 节点写入该行,但这很混乱(并且没有修复其他节点的 KeyErrors)。
在这种情况下,如果单个节点不存在或不包含任何数据,我如何在不牺牲整个条目的情况下跳过写入?
非常感谢。
如果您必须使用这样的键,我过去在网络抓取中使用的一种方法是创建一个包装器来处理错误,然后返回值。
def get_node(name, node):
try:
val = node[name]
except KeyError:
val = 'na'
return val
write.writerow(['allhomes',
get_node('bathrooms', node),
...
])
我在上面遇到了同样的问题,但 DictWriter
。 +1 @Jeff 的回答帮助了我。不得不稍微修改它来处理 Dicts,但希望能帮助其他人:
def check_val(item_value):
try:
if my_data.get(item_value):
val = something.get(item_value)
except:
val = None
return val
writer.writerow({
'item_key' : check_val('item_value'),
...
})
首先检查(通过check_val
函数)该值是否存在,如果不存在则可以避免KeyError。您还可以扩展 if
语句下的逻辑,以从嵌套列表和字典中提取数据,如果您的数据可能存在也可能不存在,这也非常有用。
我在 Python 中使用 lxml 和 JSON 库编写了一个基本的网络抓取工具。下面的代码片段详细说明了我目前如何写入 CSV:
with open(filepath, "ab") as f:
write = csv.writer(f)
try:
write.writerow(["allhomes",
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr,
'', # fill this in! should be 'description'
node["state"],
node["suburb"],
node["postcode"],
node["propertyType"],
node["bathrooms"],
node["bedrooms"],
node["parking"],
pricenode,
node["photoCount"],
node2["pricemin"],
node2["pricemax"],
node2["pricerange"]])
except KeyError, e:
try:
write.writerow(["allhomes",
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr,
'', # fill this in! should be 'description'
node["state"],
node["suburb"],
node["postcode"],
node["propertyType"],
'',
node["bedrooms"],
node["parking"],
pricenode,
node["photoCount"],
node2["pricemin"],
node2["pricemax"],
node2["pricerange"]])
except KeyError, e:
errorcount += 1
with open(filepath, "ab"): #
write = csv.writer(f)
write.writerow(["Error: invalid dictionary field key: %s" % e.args,
statenum,
statesubnum,
suburbnum,
listingnum,
listingsurlstr])
pass
pass
问题在于,如果某个节点不存在(最常见的是 Bathrooms 节点),我必须通过将 Bathrooms 节点替换为空值来重试,或者随后放弃整行数据。我目前的方法是重试并通过删除 Bathrooms 节点写入该行,但这很混乱(并且没有修复其他节点的 KeyErrors)。
在这种情况下,如果单个节点不存在或不包含任何数据,我如何在不牺牲整个条目的情况下跳过写入?
非常感谢。
如果您必须使用这样的键,我过去在网络抓取中使用的一种方法是创建一个包装器来处理错误,然后返回值。
def get_node(name, node):
try:
val = node[name]
except KeyError:
val = 'na'
return val
write.writerow(['allhomes',
get_node('bathrooms', node),
...
])
我在上面遇到了同样的问题,但 DictWriter
。 +1 @Jeff 的回答帮助了我。不得不稍微修改它来处理 Dicts,但希望能帮助其他人:
def check_val(item_value):
try:
if my_data.get(item_value):
val = something.get(item_value)
except:
val = None
return val
writer.writerow({
'item_key' : check_val('item_value'),
...
})
首先检查(通过check_val
函数)该值是否存在,如果不存在则可以避免KeyError。您还可以扩展 if
语句下的逻辑,以从嵌套列表和字典中提取数据,如果您的数据可能存在也可能不存在,这也非常有用。