You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

封装可用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:58:06