Wikidata——获取大量id的标签
Wikidata - get labels for a large number of ids
我在 ndjson 文件中列出了大约 300.000 个维基数据 ID(例如 Q1347065、Q731635 等)
{"Q1347065": ""}
{"Q731635": ""}
{"Q191789": ""} ... etc
我想要的是获取每个id的label,形成一个key值的字典,比如
{"Q1347065":"epiglottitis", "Q731635":"Mount Vernon", ...}
等
在 ID 列表变得如此庞大之前,我使用的是 Wikidata python 库 (https://pypi.org/project/Wikidata/)
from wikidata.client import Client
import ndjson
client = Client()
with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
claims = ndjson.load(f)
l = {}
for d in claims:
l.update(d)
for key in l:
v = client.get(key)
l[key] = str(v.label)
json.dumps(l, out)
但是速度太慢了(1000个id需要15小时左右)。有没有另一种方法可以比我一直在做的更快?
回答前:我不知道你json.dumps(r, out)
是什么意思;我假设你想要 json.dump(l, out)
而不是。
我的答案是使用以下 SPARQL 查询 Wikidata Query Service:
SELECT ?item ?itemLabel WHERE {
VALUES ?item { wd:Q1347065 wd:Q731635 wd:Q105492052 }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
同时询问多个标签。
这会加快 很多 你的执行时间,因为你的瓶颈是连接数,使用这种方法,id -> 标签映射完全在服务器端完成。
import json
import ndjson
import re
import requests
def wikidata_query(query):
url = 'https://query.wikidata.org/sparql'
try:
r = requests.get(url, params = {'format': 'json', 'query': query})
return r.json()['results']['bindings']
except json.JSONDecodeError as e:
raise Exception('Invalid query')
with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
claims = ndjson.load(f)
l = {}
for d in claims:
l.update(d)
item_ids = l.keys()
sparql_values = list(map(lambda id: "wd:" + id, item_ids))
item2label = wikidata_query('''
SELECT ?item ?itemLabel WHERE {
VALUES ?item { %s }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}''' % " ".join(sparql_values))
for result in item2label :
item = re.sub(r".*[#/\]", "", result['item']['value'])
label = result['itemLabel']['value']
l[item] = label
json.dump(l, out)
我猜你无法对所有 300.000 个项目进行一次查询,但你可以轻松找到最大支持数量的已接受 ID 并根据该数量拆分你的原始 ID 列表。
我在 ndjson 文件中列出了大约 300.000 个维基数据 ID(例如 Q1347065、Q731635 等)
{"Q1347065": ""}
{"Q731635": ""}
{"Q191789": ""} ... etc
我想要的是获取每个id的label,形成一个key值的字典,比如
{"Q1347065":"epiglottitis", "Q731635":"Mount Vernon", ...}
等
在 ID 列表变得如此庞大之前,我使用的是 Wikidata python 库 (https://pypi.org/project/Wikidata/)
from wikidata.client import Client
import ndjson
client = Client()
with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
claims = ndjson.load(f)
l = {}
for d in claims:
l.update(d)
for key in l:
v = client.get(key)
l[key] = str(v.label)
json.dumps(l, out)
但是速度太慢了(1000个id需要15小时左右)。有没有另一种方法可以比我一直在做的更快?
回答前:我不知道你json.dumps(r, out)
是什么意思;我假设你想要 json.dump(l, out)
而不是。
我的答案是使用以下 SPARQL 查询 Wikidata Query Service:
SELECT ?item ?itemLabel WHERE {
VALUES ?item { wd:Q1347065 wd:Q731635 wd:Q105492052 }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
同时询问多个标签。
这会加快 很多 你的执行时间,因为你的瓶颈是连接数,使用这种方法,id -> 标签映射完全在服务器端完成。
import json
import ndjson
import re
import requests
def wikidata_query(query):
url = 'https://query.wikidata.org/sparql'
try:
r = requests.get(url, params = {'format': 'json', 'query': query})
return r.json()['results']['bindings']
except json.JSONDecodeError as e:
raise Exception('Invalid query')
with open("claims.ndjson") as f, open('claims_to_strings.json', 'w') as out:
claims = ndjson.load(f)
l = {}
for d in claims:
l.update(d)
item_ids = l.keys()
sparql_values = list(map(lambda id: "wd:" + id, item_ids))
item2label = wikidata_query('''
SELECT ?item ?itemLabel WHERE {
VALUES ?item { %s }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}''' % " ".join(sparql_values))
for result in item2label :
item = re.sub(r".*[#/\]", "", result['item']['value'])
label = result['itemLabel']['value']
l[item] = label
json.dump(l, out)
我猜你无法对所有 300.000 个项目进行一次查询,但你可以轻松找到最大支持数量的已接受 ID 并根据该数量拆分你的原始 ID 列表。