为何Python urllib3向Wikidata SPARQL端点发POST请求失败,而requests可行?
解决urllib3调用Wikidata SPARQL接口返回405 "Not writable"的问题
当用urllib3以POST方式调用Wikidata Query Service的SPARQL接口时出现405错误,返回"Not writable",但相同逻辑的requests代码可正常运行,核心原因是urllib3的fields参数会自动把请求编码为multipart/form-data格式,而非预期的application/x-www-form-urlencoded——即便手动设置了Content-Type头,urllib3也会覆盖该值,导致服务端无法识别查询请求格式,误判为写入操作从而返回错误。
修正后的urllib3代码
需手动将查询参数编码为URL格式字符串,通过body参数传递,同时保留正确请求头:
import urllib3 import urllib.parse query_string = 'SELECT ?item WHERE {?item wdt:P31 wd:Q146.}LIMIT 10' # 手动编码查询参数为application/x-www-form-urlencoded格式 encoded_data = urllib.parse.urlencode({'query': query_string}) http = urllib3.PoolManager() requestheader = { 'User-Agent': 'TestAgent/0.1 (mailto:email@domain.com)', 'Accept': 'application/sparql-results+json', 'Content-Type': 'application/x-www-form-urlencoded' } # 使用body参数传递编码后的数据,替代原fields参数 response = http.request('POST', 'https://query.wikidata.org/sparql', body=encoded_data, headers=requestheader) print(response.status) print(response.headers) print(response.data.decode('utf-8'))
关键修改说明
- 用
urllib.parse.urlencode()将查询参数编码为符合要求的URL格式字符串 - 替换
fields参数为body参数传递数据,避免urllib3强制使用multipart/form-data编码 - 确保
Content-Type头保持为application/x-www-form-urlencoded,此时urllib3不会覆盖该头
内容的提问来源于stack exchange,提问作者Steve Baskauf
相关产品推荐
相关产品推荐

