封装可用SPARQL查询至Python代码时遇JSONDecodeError求助
SPARQL查询封装Python遇JSONDecodeError,求异常捕获方案
我把一段可正常运行的SPARQL查询整合进Python代码,原本想避免超时问题,结果碰到报错:JSONDecodeError: Expecting value: line 1 column 1 (char 0)。我知道得加异常捕获,但不知道具体怎么写,原代码如下:
#! /usr/bin/env python3 from qwikidata.sparql import return_sparql_query_results import json data = return_sparql_query_results(""" SELECT DISTINCT ?poi ?itemLabel_es ?itemLabel_en ?itemLabel_ceb ?itemLabel_ca ?itemLabel_gl ?itemLabel_eu ?itemLabel_ru ?itemLabel_uk ?typeLabel ?localizationLabel WHERE { #here change: wd:Q for country ?poi (p:P17/ps:P17) wd:Q29. #here change: adapt all UNION statements, remove which not needed, change wd:Q for feature types for UNION statements { ?poi p:P31/ps:P31/wdt:P279* wd:Q10354598. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q532. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q4632675. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q699405. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q5084. } #here change: adapt all language lables, remove which not needed, language code can be taken from wikidata OPTIONAL { ?poi rdfs:label ?itemLabel_es. FILTER((LANG(?itemLabel_es)) = "es") } OPTIONAL { ?poi rdfs:label ?itemLabel_en. FILTER((LANG(?itemLabel_en)) = "en") } OPTIONAL { ?poi rdfs:label ?itemLabel_ceb. FILTER((LANG(?itemLabel_ceb)) = "ceb") } OPTIONAL { ?poi rdfs:label ?itemLabel_ca. FILTER((LANG(?itemLabel_ca)) = "ca") } OPTIONAL { ?poi rdfs:label ?itemLabel_gl. FILTER((LANG(?itemLabel_gl)) = "gl") } OPTIONAL { ?poi rdfs:label ?itemLabel_eu. FILTER((LANG(?itemLabel_eu)) = "eu") } OPTIONAL { ?poi rdfs:label ?itemLabel_ru. FILTER((LANG(?itemLabel_ru)) = "ru") } OPTIONAL { ?poi rdfs:label ?itemLabel_uk. FILTER((LANG(?itemLabel_uk)) = "uk") } OPTIONAL{ ?poi p:P31/ps:P31 ?type SERVICE wikibase:label { ?type rdfs:label ?typeLabel . bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } OPTIONAL{ ?poi p:P131/ps:P131 ?localization SERVICE wikibase:label { ?localization rdfs:label ?localizationLabel . bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } } Limit 50000 """) encodedUnicode = json.dumps(data, ensure_ascii=False) decodingJSON = json.loads(encodedUnicode, strict=False) with open ('data_smple.txt', 'w') as target_file: target_file.write(json.dumps(decodingJSON, indent=4)) print(repr(data[24257164-20:24257164+20]))
问题排查与解决办法
1. 错误根源
这个报错本质是return_sparql_query_results返回的内容不是合法JSON——大概率是请求超时返回空响应、服务器返回错误页面,或者查询结果太大导致传输中断。
2. 异常捕获+重试实现
给请求加上超时控制,同时捕获JSON解析异常和请求异常,配合重试逻辑,避免单次请求失败直接崩溃。修改后的代码如下:
#! /usr/bin/env python3 from qwikidata.sparql import return_sparql_query_results import json import time from requests.exceptions import RequestException def get_sparql_results(query, max_retries=3, timeout=30): for attempt in range(max_retries): try: # 设置超时时间,避免无限等待 data = return_sparql_query_results(query, timeout=timeout) return data except json.JSONDecodeError as e: print(f"JSON解析失败,重试第{attempt+1}次: {e}") time.sleep(2) except RequestException as e: print(f"请求出错,重试第{attempt+1}次: {e}") time.sleep(2) raise Exception(f"重试{max_retries}次后仍失败") # 原SPARQL查询 sparql_query = """ SELECT DISTINCT ?poi ?itemLabel_es ?itemLabel_en ?itemLabel_ceb ?itemLabel_ca ?itemLabel_gl ?itemLabel_eu ?itemLabel_ru ?itemLabel_uk ?typeLabel ?localizationLabel WHERE { ?poi (p:P17/ps:P17) wd:Q29. { ?poi p:P31/ps:P31/wdt:P279* wd:Q10354598. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q532. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q4632675. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q699405. } UNION { ?poi p:P31/ps:P31/wdt:P279* wd:Q5084. } OPTIONAL { ?poi rdfs:label ?itemLabel_es. FILTER(LANG(?itemLabel_es) = "es") } OPTIONAL { ?poi rdfs:label ?itemLabel_en. FILTER(LANG(?itemLabel_en) = "en") } OPTIONAL { ?poi rdfs:label ?itemLabel_ceb. FILTER(LANG(?itemLabel_ceb) = "ceb") } OPTIONAL { ?poi rdfs:label ?itemLabel_ca. FILTER(LANG(?itemLabel_ca) = "ca") } OPTIONAL { ?poi rdfs:label ?itemLabel_gl. FILTER(LANG(?itemLabel_gl) = "gl") } OPTIONAL { ?poi rdfs:label ?itemLabel_eu. FILTER(LANG(?itemLabel_eu) = "eu") } OPTIONAL { ?poi rdfs:label ?itemLabel_ru. FILTER(LANG(?itemLabel_ru) = "ru") } OPTIONAL { ?poi rdfs:label ?itemLabel_uk. FILTER(LANG(?itemLabel_uk) = "uk") } OPTIONAL{ ?poi p:P31/ps:P31 ?type SERVICE wikibase:label { ?type rdfs:label ?typeLabel . bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } OPTIONAL{ ?poi p:P131/ps:P131 ?localization SERVICE wikibase:label { ?localization rdfs:label ?localizationLabel . bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } } } Limit 50000 """ try: data = get_sparql_results(sparql_query) # 去掉冗余的JSON转码,直接写入文件 with open('data_smple.txt', 'w', encoding='utf-8') as target_file: json.dump(data, target_file, indent=4, ensure_ascii=False) print("数据写入成功") except Exception as e: print(f"最终失败: {e}")
3. 额外优化建议
- 移除冗余JSON操作:原代码里
json.dumps再json.loads完全没必要,直接用return_sparql_query_results返回的字典即可 - 分批次查询:50000条结果太大,建议用
OFFSET分页,比如每次查1000条,循环获取所有结果,降低服务器压力 - 简化SPARQL标签查询:把多语言标签查询改成
SERVICE wikibase:label的方式,更简洁高效,比如:SERVICE wikibase:label { ?poi rdfs:label ?itemLabel_es. ?poi rdfs:label ?itemLabel_en. bd:serviceParam wikibase:language "es,en,ceb,ca,gl,eu,ru,uk". }
内容的提问来源于stack exchange,提问作者Elart
相关产品推荐
相关产品推荐

