match_all.py为在json补充xkw_code字段的脚本, check_xkw_codes.py为检查xkw_code与url_id不一致的脚本
This commit is contained in:
48
zq/check_xkw_codes.py
Normal file
48
zq/check_xkw_codes.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import json
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
jsons_dir = Path(__file__).parent / "jsons"
|
||||||
|
output_file = Path(__file__).parent / "mismatched_codes.json"
|
||||||
|
|
||||||
|
mismatches = []
|
||||||
|
|
||||||
|
for json_file in sorted(jsons_dir.glob("*.json")):
|
||||||
|
with open(json_file, encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
for item in data.get("items", []):
|
||||||
|
url = item.get("url", "")
|
||||||
|
xkw_code = item.get("xkw_code", "")
|
||||||
|
|
||||||
|
if "www.zxxk.com" not in url:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Extract numeric ID from URL (e.g. /soft/38079968.html or ?id=38079968)
|
||||||
|
match = re.search(r"[\\/](\d+)(?:\.\w+)?(?:\?|$)", url)
|
||||||
|
if not match:
|
||||||
|
match = re.search(r"[?&](?:id|soft)=(\d+)", url)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
|
||||||
|
url_id = match.group(1)
|
||||||
|
|
||||||
|
if str(xkw_code) == "0":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if url_id != str(xkw_code):
|
||||||
|
mismatches.append({
|
||||||
|
"source_file": json_file.name,
|
||||||
|
"filename": item.get("filename", []),
|
||||||
|
"title": item.get("title", ""),
|
||||||
|
"url": url,
|
||||||
|
"url_id": url_id,
|
||||||
|
"xkw_code": xkw_code,
|
||||||
|
})
|
||||||
|
|
||||||
|
with open(output_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(mismatches, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
print(f"检查完成:共发现 {len(mismatches)} 条不一致记录,已输出到 {output_file}")
|
||||||
145
zq/match_all.py
Normal file
145
zq/match_all.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# 遍历 jsons/ 目录下所有 JSON 文件,按 URL 来源匹配 Excel 暗码:
|
||||||
|
# - url 含 www.21cnjy.com → 在 "21世纪资料名" 列精确匹配 filename[0]
|
||||||
|
# - url 含 www.zxxk.com → 在 "学科网资料名" 列精确匹配 filename[0]
|
||||||
|
# 学科网资料名有重复时,从 item 的 url 中提取数字 ID 与各暗码候选值比对消歧
|
||||||
|
# - 匹配成功写入 xkw_code,未匹配写入 "0"
|
||||||
|
# - 未匹配数据汇总写入 问题数据/未匹配填充0.json
|
||||||
|
|
||||||
|
import json # 用于读写 JSON 文件
|
||||||
|
import re # 用于正则表达式提取 URL 中的数字 ID
|
||||||
|
import glob # 用于批量匹配目录下的文件路径
|
||||||
|
import openpyxl # 用于读取 Excel (.xlsx) 文件
|
||||||
|
|
||||||
|
EXCEL_PATH = "结果.xlsx" # Excel 数据文件路径
|
||||||
|
JSON_DIR = "jsons" # JSON 文件所在目录
|
||||||
|
UNMATCHED_OUT = "问题数据/未匹配填充0.json" # 未匹配数据输出路径
|
||||||
|
|
||||||
|
|
||||||
|
def clean(v):
|
||||||
|
# 将单元格值转为字符串并去除首尾空格
|
||||||
|
if not v:
|
||||||
|
return "" # 空值直接返回空字符串
|
||||||
|
s = str(v).strip() # 转字符串并去首尾空白
|
||||||
|
if s.startswith("'"):
|
||||||
|
s = s[1:] # 去掉 Excel 强制文本时产生的前导单引号(如以 + 开头的单元格)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def load_excel_indexes(path):
|
||||||
|
# 读取 Excel 文件,构建两个查找字典
|
||||||
|
# 返回:
|
||||||
|
# map_21: {21世纪资料名 → 暗码}
|
||||||
|
# map_xkw: {学科网资料名 → [暗码, ...]} (同名可能对应多个暗码,全部保留)
|
||||||
|
wb = openpyxl.load_workbook(path) # 打开 Excel 文件
|
||||||
|
ws = wb.active # 取活动工作表
|
||||||
|
headers = [cell.value for cell in ws[1]] # 读取第一行作为列名
|
||||||
|
col = {h: i for i, h in enumerate(headers)} # 构建列名到列索引的映射
|
||||||
|
|
||||||
|
idx_21 = col["21世纪资料名"] # "21世纪资料名" 列的索引
|
||||||
|
idx_xkw = col["学科网资料名"] # "学科网资料名" 列的索引
|
||||||
|
idx_code = col["暗码"] # "暗码" 列的索引
|
||||||
|
|
||||||
|
map_21 = {} # 21世纪资料名 → 暗码(唯一映射,重复则后者覆盖前者)
|
||||||
|
map_xkw = {} # 学科网资料名 → [暗码列表](同名保留全部暗码)
|
||||||
|
for row in ws.iter_rows(min_row=2, values_only=True): # 从第2行开始逐行读取
|
||||||
|
code = clean(row[idx_code]) # 读取并清洗暗码
|
||||||
|
name_21 = clean(row[idx_21]) # 读取并清洗 21世纪资料名
|
||||||
|
name_xkw = clean(row[idx_xkw]) # 读取并清洗学科网资料名
|
||||||
|
if name_21 and code:
|
||||||
|
map_21[name_21] = code # 写入 21世纪索引
|
||||||
|
if name_xkw and code:
|
||||||
|
map_xkw.setdefault(name_xkw, []).append(code) # 追加到学科网索引列表
|
||||||
|
|
||||||
|
return map_21, map_xkw # 返回两个索引字典
|
||||||
|
|
||||||
|
|
||||||
|
def extract_url_id(url):
|
||||||
|
# 从学科网 URL 中提取纯数字资源 ID
|
||||||
|
# 例如 https://www.zxxk.com/soft/38079968.html → '38079968'
|
||||||
|
m = re.search(r'/(\d+)(?:\.\w+)?(?:\?|$)', url) # 匹配路径最后一段的纯数字
|
||||||
|
return m.group(1) if m else None # 有匹配则返回数字字符串,否则返回 None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_xkw_code(fn0, url, map_xkw):
|
||||||
|
# 学科网资料名匹配逻辑:
|
||||||
|
# - 无匹配 → 返回 None
|
||||||
|
# - 只有一个唯一暗码 → 直接返回
|
||||||
|
# - 多个不同暗码(同名不同资源)→ 用 URL ID 消歧,找到匹配则返回,否则返回 None
|
||||||
|
codes = map_xkw.get(fn0) # 查找该文件名对应的暗码列表
|
||||||
|
if not codes:
|
||||||
|
return None # 在学科网索引中找不到该文件名
|
||||||
|
unique_codes = list(dict.fromkeys(codes)) # 去重并保持原顺序
|
||||||
|
if len(unique_codes) == 1:
|
||||||
|
return unique_codes[0] # 唯一暗码,直接返回
|
||||||
|
url_id = extract_url_id(url) # 从 URL 中提取数字 ID
|
||||||
|
if url_id and url_id in codes:
|
||||||
|
return url_id # URL ID 与某个暗码一致,用该值
|
||||||
|
return None # 无法消歧,返回 None
|
||||||
|
|
||||||
|
|
||||||
|
def process_file(json_path, map_21, map_xkw):
|
||||||
|
# 处理单个 JSON 文件:为每个 item 写入 xkw_code
|
||||||
|
with open(json_path, encoding="utf-8") as f:
|
||||||
|
data = json.load(f) # 读取 JSON 数据
|
||||||
|
|
||||||
|
matched = 0 # 成功匹配的计数
|
||||||
|
unmatched_items = [] # 未匹配的 item 列表,用于汇总输出
|
||||||
|
|
||||||
|
for item in data.get("items", []): # 遍历每个资源 item
|
||||||
|
fns = item.get("filename", []) # 读取 filename 列表
|
||||||
|
if not fns:
|
||||||
|
continue # filename 为空则跳过该 item
|
||||||
|
fn0 = fns[0].strip() # 只取第一个 filename 并去空格
|
||||||
|
url = item.get("url", "") # 读取该 item 的 URL
|
||||||
|
|
||||||
|
code = None # 初始化暗码为空
|
||||||
|
if "www.21cnjy.com" in url:
|
||||||
|
code = map_21.get(fn0) # 在 21世纪索引中精确查找
|
||||||
|
elif "www.zxxk.com" in url:
|
||||||
|
code = resolve_xkw_code(fn0, url, map_xkw) # 在学科网索引中查找(含消歧)
|
||||||
|
|
||||||
|
if code:
|
||||||
|
item["xkw_code"] = code # 匹配成功,写入暗码
|
||||||
|
matched += 1 # 匹配计数加一
|
||||||
|
else:
|
||||||
|
item["xkw_code"] = "0" # 未匹配,填充 "0"
|
||||||
|
unmatched_items.append({
|
||||||
|
"source_file": json_path, # 来源 JSON 文件路径
|
||||||
|
"filename": fn0, # 未匹配的文件名
|
||||||
|
"url": url, # 对应的 URL
|
||||||
|
})
|
||||||
|
|
||||||
|
with open(json_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2) # 将修改后的数据写回 JSON 文件
|
||||||
|
|
||||||
|
return matched, unmatched_items # 返回匹配数和未匹配列表
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("加载 Excel 索引...")
|
||||||
|
map_21, map_xkw = load_excel_indexes(EXCEL_PATH) # 构建 Excel 查找索引
|
||||||
|
print(f"Excel 索引:21世纪 {len(map_21)} 条,学科网 {len(map_xkw)} 个不重复名称\n")
|
||||||
|
|
||||||
|
files = sorted(glob.glob(f"{JSON_DIR}/*.json")) # 获取所有 JSON 文件路径并排序
|
||||||
|
total_files = len(files) # JSON 文件总数
|
||||||
|
total_matched = 0 # 全局匹配计数
|
||||||
|
all_unmatched = [] # 全局未匹配列表
|
||||||
|
|
||||||
|
for i, path in enumerate(files, 1): # 逐个处理每个 JSON 文件
|
||||||
|
matched, unmatched_items = process_file(path, map_21, map_xkw) # 处理单文件
|
||||||
|
total_matched += matched # 累加匹配数
|
||||||
|
all_unmatched.extend(unmatched_items) # 合并未匹配列表
|
||||||
|
print(f"[{i}/{total_files}] {path} 匹配:{matched} 未匹配:{len(unmatched_items)}")
|
||||||
|
|
||||||
|
with open(UNMATCHED_OUT, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(all_unmatched, f, ensure_ascii=False, indent=2) # 写出所有未匹配数据
|
||||||
|
|
||||||
|
total_unmatched = len(all_unmatched) # 全局未匹配总数
|
||||||
|
print(f"\n完成:处理 {total_files} 个文件,写入 xkw_code {total_matched + total_unmatched} 条"
|
||||||
|
f"(匹配:{total_matched},填0:{total_unmatched})")
|
||||||
|
print(f"未匹配数据已保存至 {UNMATCHED_OUT}") # 提示未匹配数据保存路径
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main() # 脚本直接运行时执行 main 函数
|
||||||
4382
zq/问题数据/未匹配填充0.json
Normal file
4382
zq/问题数据/未匹配填充0.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user