当前位置: 首页 > article >正文

2026春SDU软件创新实训第四周个人工作总结

第四周我做的工作总结如下从原始网页爬取科一科四题库书接上期我们找到了两个网页的题库驾照吧https://www.jiazhaoba.com/tiba元贝驾考https://www.ybjk.com/tiku其中的题目是以链表的形式前后存储的。这里我提取的思路是下载一页题目HTML的样例页代码把它作为提示词输入给LLM首先让它分析网页的代码按照不同种类题目单选、多选、判断三类找出我们要提取的题干、选项、解析、图中图片等信息所对应的HTML标签同时给出一个输出的样例模板让它首先通过爬虫技术提取出这些关键信息再将这些信息按照模板结构输出为json格式的文件主体对话如下上图是给定样例网页代码。上图定义了我们期望得到的json结构内容有题干question类型type选项判断题默认两个选项、答案key、解析以及上一页和下一页的链接url主要是方便我们断点重传涉及图片的也要提取img标签保存到对应服务器路径下并且img字段是非空的保存图片结构声明如下单页题目提取完毕后我们期望爬虫脚本能根据next_url的链接值自动跳转到下一题下一个页面直到到达链尾停止页面上没有next标签了。综合上述关键词LLM给出的分析结果如下初步给出的代码如下import os import json import time import random import requests from bs4 import BeautifulSoup from urllib.parse import urljoin # ── 配置项 ──────────────────────────────────────────────── BASE_URL https://www.jiazhaoba.com START_URL https://www.jiazhaoba.com/tiba/1/ OUTPUT_FILE subject4_questions.json IMAGE_DIR subject1_images # 伪装请求头 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Referer: https://www.jiazhaoba.com/tiba/ } # ── 工具函数 ────────────────────────────────────────────── def ensure_env(): if not os.path.exists(IMAGE_DIR): os.makedirs(IMAGE_DIR) def load_data(): 读取已有数据实现断点续爬 if os.path.exists(OUTPUT_FILE): try: with open(OUTPUT_FILE, r, encodingutf-8) as f: return json.load(f) except: return [] return [] def save_data(data): 保存数据到JSON with open(OUTPUT_FILE, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) def download_img(session, img_url, q_index): 下载图片命名格式题号_1.jpg if not img_url: return None full_url urljoin(BASE_URL, img_url) try: ext full_url.split(.)[-1] if . in full_url else jpg filename f{q_index}_1.{ext} filepath os.path.join(IMAGE_DIR, filename) # 避免重复下载 if os.path.exists(filepath): return filepath r session.get(full_url, timeout10) if r.status_code 200: with open(filepath, wb) as f: f.write(r.content) return filepath except Exception as e: print(f [Error] 图片下载失败: {e}) return None # ── 核心爬取逻辑 ────────────────────────────────────────── def scrape(): ensure_env() session requests.Session() session.headers.update(HEADERS) questions load_data() visited_urls {q[url] for q in questions} # 确定起点 current_url START_URL if questions and questions[-1].get(next_url): current_url questions[-1][next_url] print(f[*] 检测到历史记录从断点继续: {current_url}) count len(questions) while current_url: if current_url in visited_urls: print(f[!] 检测到重复URL或环路停止: {current_url}) break print(f\n[{time.strftime(%H:%M:%S)}] 正在爬取第 {count 1} 题: {current_url}) try: resp session.get(current_url, timeout15) resp.encoding utf-8 soup BeautifulSoup(resp.text, html.parser) # --- 1. 提取题干与选项 --- topic_box soup.select_one(.topic-l ul) if not topic_box: print( [Error] 未能找到题目容器可能触发反爬或结构变化) break lis topic_box.find_all(li, recursiveFalse) raw_question lis[0].get_text(stripTrue) # 过滤掉 class 为 answer 的 li提取纯选项 option_items [li.get_text(stripTrue) for li in lis[1:] if answer not in li.get(class, [])] # --- 2. 提取答案与解析 --- answer_tag soup.select_one(.answer strong) key answer_tag.get_text(stripTrue) if answer_tag else analysis_tag soup.select_one(.topic-b.analy-note p) analysis analysis_tag.get_text(stripTrue) if analysis_tag else # --- 3. 提取图片 --- img_tag soup.select_one(.imgorvideo img) img_path None if img_tag: img_path download_img(session, img_tag.get(src), count 1) # --- 4. 判定题目类型 --- # 如果选项包含“正确”“错误”且只有两个判为 judge if len(option_items) 2: q_type judge else: q_type single_choose # --- 5. 获取下一页链接 --- next_url None # 查找“下一题”所在的 a 标签 next_link_tag soup.find(label, string下一题) if next_link_tag: a_tag next_link_tag.find_next_sibling(a) if a_tag: next_url urljoin(BASE_URL, a_tag.get(href)) # 如果上面方法没找到尝试在整个 .preandnext 区域搜寻 if not next_url: for div in soup.select(.preandnext div): if 下一题 in div.get_text(): a div.find(a) if a: next_url urljoin(BASE_URL, a.get(href)) # --- 6. 构造数据并保存 --- item { question: raw_question, type: q_type, img: img_path, options: option_items, key: key, analysis: analysis, url: current_url, next_url: next_url } questions.append(item) visited_urls.add(current_url) save_data(questions) count 1 # Debug 输出 print(f 题干: {raw_question[:30]}...) print(f 类型: {q_type} | 答案: {key} | 图片: {img_path}) print(f 下一题: {next_url}) # 退出条件 if not next_url: print(\n[√] 已到达最后一题爬取结束。) break # 随机延迟保护 delay random.uniform(2.0, 4.0) time.sleep(delay) current_url next_url except Exception as e: print(f [Fatal Error] 爬取中断: {e}) break print(f\n{*30}) print(f统计: 共计获取 {len(questions)} 道题目) print(f结果已保存至: {OUTPUT_FILE}) if __name__ __main__: scrape()正当满心欢喜的使用这个脚本直接提取1000题目时候现实出现了这样的问题与LLM交流后我明白了“爬取”的过程也是需要遵循规则的网站后台的服务器会记录每个IP地址的访问频率如果访问过快就会被视为机器人程序而非真人导致IP被临时封锁无法继续读取。吸取了这个教训我在LLM的建议下加入了预热机制模拟真实人类浏览顺序先到主页再到题目页面还提高了每两题之间的等待时间等待大约4s左右确保符合人类阅读时间防止出发封禁def warmup(session): 先模拟人工浏览几个页面再开始爬题 pages [ (https://www.ybjk.com/, None), (https://www.ybjk.com/tiku/, https://www.ybjk.com/), (https://www.ybjk.com/tiku/kms.htm,https://www.ybjk.com/tiku/), ] print([预热] 模拟人工浏览...) for url, ref in pages: try: r session.get(url, timeout20, proxiesPROXY, headersmake_headers(ref)) print(f {url} → {r.status_code} ({len(r.content)} bytes)) except Exception as e: print(f [预热失败] {url} - {e}) time.sleep(random.uniform(2.0, 4.0)) print([预热完成]\n)在这个过程中还是有意外发生的网站实际的链接顺序有问题中间存在跳跃现象漏掉了几百题针对这个问题我微调了一下代码利用url中编号自增的顺序手动补充上了剩下的几百题经过上面的操作我成功爬取了1309道科目一的题目和1126道科目四的题目基本能够满足搭建一个小型驾考APP的数据量了调研所得大部分APP科一题目量在1700科四在1200。效果预览如下{ question: 路面上的黄色标线是何含义, type: single_choose, img: subject1_images\\948_1.jpg, options: [ A、车行道变多标线, B、路面宽度渐变标线, C、接近障碍物标线, D、施工路段提示线 ], key: B, analysis: 该标志为路面宽度渐变标线。, url: https://www.jiazhaoba.com/tiba/868/, next_url: https://www.jiazhaoba.com/tiba/9264/ }, { question: 夜间行车驾驶人视距变短影响观察同时注意力高度集中易产生疲劳。, type: judge, img: null, options: [ A、正确, B、错误 ], key: A, analysis: 高度集中注意力很费神的久了就会疲倦。, url: https://www.jiazhaoba.com/tiba/893/, next_url: https://www.jiazhaoba.com/tiba/9264/ }, { question: 林某驾车以110公里/小时的速度在城市道路行驶与一辆机动车追尾后弃车逃离被群众拦下。经鉴定事发时林某血液中的酒精浓度为135.8毫克/百毫升。林某的主要违法行为是什么, type: multi_choose, img: null, options: [ A、醉酒驾驶, B、超速驾驶, C、疲劳驾驶, D、肇事逃逸 ], key: ABD, analysis: 根据法律规定和题干信息\n林某的行为\n构成以下三项违法行为\n1、【\n城三五\n公四七】\n城市道路限速规定\n无中心线30公里/小时有中心线50公里/小时林某110公里/小时的速度行驶属于\n超速驾驶\n\n2、追尾后\n弃车逃离\n属于\n肇事逃逸\n\n3、血液中酒精含量在\n80毫克/百毫升含以上\n属于\n醉酒驾驶\n。\n而题目中没有任何信息如“连续驾驶X小时”、“感觉困倦”等表明林某存在疲劳驾驶的行为。因此不能凭主观臆断选择此项。, url: https://www.ybjk.com/tiku/07f6d.htm, next_url: https://www.ybjk.com/tiku/ed8f7.htm },保存了对应题目的图片至此我们就成功提取出来了所需的题库信息他们将成为整个项目的数据基础的一部分为科一科四题库添加标签我和队友针对每个题目各自考察的重点结合原始网页题库中的题目描述对原有down下来的题目进行了重新的标签划分主要步骤如下将原始的题库送入LLM由它结合检索到的驾驶人考试大纲的细节根据题目类型和情境的分布对科一和科四的1000题分别进行标签的分类并且明确定义每一类标签的题目的含义由本人和队友讨论确定无误后确定下来回答的分类方式如下科目一题目分类方式确定如上科目四同理此处略。随后我们基于分类好的标签分类标准编写脚本调用通用LLM的API来给每一个题目进行类别的智能分类并且详细规定返回格式同时一旦返回格式不符合要求就重新请求。首先是提示词设计我们需要把题目分类依据和方式说明清楚并且要设计好输出json的结构格式确保返回的结果可以直接解析下列代码均由LLM产生BATCH_SIZE 10 # 每批处理的题目数量建议 10-20 之间 SLEEP_TIME 3 # 每批之间的休息时间 VALID_LABELS [ 法律法规与违法处罚, 驾驶证与车辆管理规定, 交通标志、标线与信号灯, 交通警察手势含义, 驾驶操作基础与仪表常识, 一般道路安全驾驶策略, 高速公路及特殊路环境驾驶, 紧急避险与事故处理常识 ] client openai.OpenAI(api_keyAPI_KEY, base_urlBASE_URL) # --- 提示词模板 --- LABEL_DEFINITIONS 1. 法律法规与违法处罚侧重法律定性违法行为、处罚标准扣分、罚款、拘役、吊销、法律责任。 2. 驾驶证与车辆管理规定侧重准驾车型、申领流程、换证时间、丢失补办、车辆登记/报废、审验规定。 3. 交通标志、标线与信号灯侧重识别图片中的标志牌、地面标线实线、虚线、导向线以及红绿灯信号含义。 4. 交通警察手势含义侧重识别交警各种手势停止、转弯、变道等对应的指令。 5. 驾驶操作基础与仪表常识侧重车内按键灯光、雨刮、空调、仪表盘符号冷却液、机油、ABS、安全带、自动挡位等。 6. 一般道路安全驾驶策略侧重普通路口的转弯礼让、跟车距离、超车/会车规范、灯光切换、文明行车等符合安全、道德和交通法律的行为。 7. 高速公路及特殊路环境驾驶侧重高速公路特有规定限速、车道、进出、恶劣天气雨雪雾、山区、隧道、桥梁驾驶方式。 8. 紧急避险与事故处理常识侧重车辆故障爆胎、刹车失灵、伤员急救止血、搬运、事故现场保护、报警处理等意外状态的操作。 SYSTEM_PROMPT f你是一个驾驶员考试题库标注专家。请为提供的题目组选择最合适的知识点标签。 标准标签库{VALID_LABELS} 标签定义{LABEL_DEFINITIONS} 输出规则 1. 必须严格按照以下 JSON 格式返回禁止任何额外文字。 2. 每个题目给出 1-2 个标签存入列表之中。优先选择1个最核心标签。若确实涉及两个领域用中文逗号“”分隔。 3. 标签必须完全匹配标准标签库中的名称严禁自己创造标签。 优先选择1个最核心标签。若确实涉及两个领域用中文逗号“”分隔。 格式示例请严格按照这个来无需其余任何说明 [ {{index: 0, labels: [法律法规与违法处罚]}}, {{index: 1, labels: [交通标志、标线与信号灯, 一般道路安全驾驶策略]}} ] 这里的LLM接口用的是推理时代这个中转平台的资源每日有重置的免费额度我们优先将每个题目绑定到它最贴切的一个标签上如果确实涉及多个标签再额外绑定。这种方法确保了标签识别的准确性尽可能减少了明显不同类型的题目却拥有同一个标签的情况。另外由于LLM输出的黑盒性质即使提示词设计的很严格仍然有可能出现不期望出现的多余输出对于这种情况也要进行判断和捕捉重新构造一次问答提取核心逻辑为while True: try: payload { model: MODEL, messages: [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: f请标注以下题目\n{prompt_content}} ], thinking: {type: disabled}, max_tokens: 8192, temperature: 0.2 } headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } response requests.post(BASE_URL, headersheaders, datajson.dumps(payload), timeout60) res_data_raw response.json() #print(返回内容:,res_data_raw) # 提取内容 res_raw res_data_raw[choices][0][message][content].strip() # 清理 Markdown 代码块 res_json_str re.sub(r^json\s*|$, , res_raw, flagsre.MULTILINE) # 解析并提取真正的 JSON 数组 # 有时模型会把思考过程和JSON混在一起这里只取 [...] 部分 json_match re.search(r\[\s*\{.*\}\s*\], res_json_str, re.DOTALL) if json_match: res_json_str json_match.group() labels_result json.loads(res_json_str) if len(labels_result) ! len(batch_list): print(f [校验失败] 数量不匹配重试...) continue final_labels [] for entry in labels_result: valid_labels [l for l in entry.get(labels, []) if l in VALID_LABELS] final_labels.append(valid_labels if valid_labels else [一般道路安全驾驶策略]) return final_labels except Exception as e: print(f [Error] 请求或解析异常: {e}10秒后重试...) time.sleep(10)这样我们就成功完成了题库的标签标注它有利于我们后续的专项学习、定点推荐等功能的实施。效果预览如下{ question: 正面安全气囊与什么配合才能充分发挥保护作用, type: single_choose, img: subject1_images\\1309_1.jpg, options: [ A、座椅安全带, B、防抱死制动系统, C、座椅安全头枕, D、安全玻璃 ], key: A, analysis: 研究表明假设气囊加安全带是100%安全的话安全带的作用是70%气囊的作用是30%。, url: https://www.jiazhaoba.com/tiba/1229/, next_url: https://www.jiazhaoba.com/tiba/9264/, label: [ 驾驶操作基础与仪表常识 ] }整理补充知识库文件这一部分我们将基于上面提取出来的标签对这些不同标签可能所对应需要的知识库进行了梳理通过长期和LLM的对话讨论最终生成了一个excel文件描述了每一类标签的题目所需要对应的知识库文件最终梳理出这个文件有些之前已经找了有些还没有通过各种渠道我们找齐了这些规范性的文件并且准备进行提取法律文本提取第一步我们针对上面的六部法律文件两部国家级法律四项公安部条令进行提取这一部分是整个里面最简单的法律文本有着极其明确的条目结构可以用多层json的格式进行提取直接用脚本进行提取即可无需动用LLM的力量。我们期望的结果效果是这样的一个法律文件对应一个json文件里面按照章节和条目分为一级和二级标题。[ { chapter: 第一章 总则, source: 中华人民共和国道路交通安全法, articles: [ { title: 第一条, content: ... }, ... ] }, ... ]输出范例如上将此结构和待提取的PDF交给LLM生成提取脚本即可涉及的核心提取方法如下RE_CHAPTER re.compile(r^第[一二三四五六七八九十百]章) RE_SECTION re.compile(r^第[一二三四五六七八九十百]节) RE_ARTICLE re.compile(r^(第[一二三四五六七八九十百]条)\s*(.*)) def clean(text: str) - str: 全角空格转半角压缩连续空格去首尾空白。 text text.replace(\u3000, ) text re.sub(r {2,}, , text) return text.strip() def extract_law(docx_path: str, source: str, has_toc: bool) - list: doc Document(str(docx_path)) chapters [] cur_chapter None cur_article None # has_tocTrue遇到第二轮章标题才算正文has_tocFalse第一次就是正文 in_body not has_toc seen_chapters set() # 记录目录中见过的章标题 def save_article(): if cur_article and cur_chapter is not None: content \n.join(cur_article[lines]).strip() cur_chapter[articles].append({ title: cur_article[title], content: content, }) def save_chapter(): if cur_chapter and cur_chapter[articles]: chapters.append({ chapter: cur_chapter[name], source: source, articles: cur_chapter[articles], }) for para in doc.paragraphs: text clean(para.text) if not text: continue # ---- 章标题 ---- if RE_CHAPTER.match(text): if not in_body: # 目录区记录已见章名若该章名已见过说明正文开始了 if text in seen_chapters: in_body True # 进入正文后正常处理这一行fall through else: seen_chapters.add(text) continue # 仍在目录跳过 # 正文中遇到章标题 → 切换章节 save_article() cur_article None save_chapter() cur_chapter {name: text, articles: []} continue # ---- 节标题忽略 ---- if RE_SECTION.match(text): continue # 目录区其他内容跳过 if not in_body: continue # ---- 条目起始行 ---- m RE_ARTICLE.match(text) if m: save_article() rest m.group(2).strip() cur_article { title: m.group(1), lines: [rest] if rest else [], } continue # ---- 普通段落追加到当前条目 ---- if cur_article is not None: cur_article[lines].append(text) # 收尾 save_article() save_chapter() return chapters这个提取的核心思想就是利用文本里面的“第X章”、“第Y节”这种带有明显标识性的文字来进行正则匹配和定位找到分割地点并且按照分割点进行分层提取。成功的前提是读取完全正确没有乱码且没有其余无关信息。很幸运这些条件都满足全部一次成功。这样我们就得到了下面的提取后的json文件其余五部同理可复用这个脚本交通标志和标线的提取这一部分比较困难尝试了好久发现用脚本提取主要有以下难点原始的国家强制标准GB5768交通标志和标线是PDF格式且存在读取乱码的问题选择复制的时候会复制下来一堆奇怪的符号尝试用脚本提取会得到一堆乱码难以像上面法律文本提取时候那样利用正则匹配方式进行分割图片的提取基本依赖写死的图注位置相对窗口大小定位窗口大小一般是写死的很难完全兼容不同大小的图片导致有些图片留白过多有些则不完整文档内噪声信息实在过多如页码、页眉、页脚等往往防不胜防很容易被带偏正文提取到一半就突然新开一个章节了。。。。。。。此处省略1w字基于这样难以使用脚本直接提取的现状困局我选择退而求其次找了一个前人整理的包含大部分GB-5768标志的word文档每个标志都具有名称、样图和含义注释天然就是适合转换为Json保存的格式。当然我也进行过尝试使用脚本对这个简化后的word文档进行提取但是终究因为换行符位置难以预测、跨行信息难以对齐而宣告失败。于是我转向寻求一种更为朴素的方法在LLM时代 谁还手写脚本做这种事情啊不都是让LLM看一眼直接导出吗这在一定程度上给了我一些思路或许我们不用搞那么麻烦直接将文档内容送给LLM让它解析里面的内容并且按照要求给出结果不就行了说干就干我们发现如果把页面截取下来作为图片输入给豆老师并且要求他给出适当的输出方式就可以达到提取的效果。页面也不多因此可以尝试使用这种方法上述为问题它也根据我们设定好的规则返回了适配的结果识别相当准确的当然这个也有缺陷只能识别里面的文字图片需要我们手动截取并且保存到它所对应的路径下满足他的命名要求可能看起来比较原始但是和之前修改脚本工作量比起来至少做的都是有效工作之前是一直原地转圈悲机动车仪表盘、操纵杆界面组件提取提取的是GB4094文件这个官方文档和上面的GB5768提取类似直接使用PDF提取也有类似的问题虽然没有乱码但是仍然有随机重开新块的几率噪声也特别多。这里我发现相对于GB5768这个的提取难度和精度要小很多无需提取完整的章节结构而是只要找到所有的组件图片让每个图片的名称和描述性解析能够正常识别出来就行了。上面是第一次对话后面又增加了过滤噪声页面、页脚以及预先输出层次分析结果确认无误后在生成实际提取结果的逻辑最终的脚本如下import os import re import json import docx from pathlib import Path # 固定章节标题双验证 LEGAL { 1: 范围, 2: 规范性引用文件, 3: 术语和定义, 4: 要求, 5: 标志种类及信号装置的显示颜色, 3.1: 操纵件, 3.2: 指示器, 3.3: 信号装置, 3.4: 标志, 3.5: 相似标志, 3.6: 共用空间, 3.7: 邻近, 4.1: 基本要求, 4.2: 信号装置标志的颜色, 4.3: 标志的位置, 5.1: 汽车操纵件、指示器及信号装置中强制标示的标志及信号装置的显示颜色, 5.2: 汽车操纵件、指示器及信号装置中非强制标示的标志及信号装置的显示颜色 } # ✅ 温和清洗你要的规则 def remove_spaces(s): if not s: return return re.sub(r\s, , s) def clean_line(s): if not s: return # 全角空格 → 半角 s s.replace(\u3000, ) # 多个空格 → 一个 s re.sub(r\s, , s) # 处理编号里的空格 # 3. 1 → 3.1 s re.sub(r(\d)\s*\.\s*(\d), r\1.\2, s) # 4. 1. 1 → 4.1.1 s re.sub(r(\d\.\d)\s*\.\s*(\d), r\1.\2, s) # 去首尾 return s.strip() # 提取图片 def extract_images(doc, out_dir): os.makedirs(out_dir, exist_okTrue) # 先收集所有图片关系 image_rels [rel for rel in doc.part.rels.values() if image in rel.target_ref] total_count len(image_rels) # 遍历并使用反向索引 for i, rel in enumerate(image_rels): data rel.target_part.blob # 如果 1号变成了 51号说明顺序是倒过来的 # 计算新索引总数 - 当前索引 (例如51 - 0 51, 51 - 50 1) real_idx total_count - i with open(f{out_dir}/图{real_idx}.jpg, wb) as f: f.write(data) print(f✅ 图片提取完成共 {total_count} 张已执行反序修正。) # 读取 def load_doc(path): doc docx.Document(path) lines [] for p in doc.paragraphs: t p.text.strip() if t: lines.append(clean_line(t)) return lines, doc # 解析结构最长匹配 双验证 def parse(lines): root [] curr1 None curr2 None # 匹配 1 / 1.2 / 1.2.3 r3 re.compile(r^(\d\.\d\.\d)\s*(.*)) r2 re.compile(r^(\d\.\d)\s*(.*)) r1 re.compile(r^(\d)\s*(.*)) img_r re.compile(r图\s*(\d)) for line in lines: # ---- 三级条目 ---- m3 r3.match(line) if m3 and curr2: n, c m3.groups() imgs [fGB4094/图{g}.jpg for g in img_r.findall(c)] curr2[children].append({ number: n, content: remove_spaces(c), images: imgs }) continue # ---- 二级标题双验证---- m2 r2.match(line) if m2: n, t m2.groups() if n in LEGAL and LEGAL[n] in line: node { number: n, title: LEGAL[n], content: , children: [] } if curr1: curr1[children].append(node) curr2 node continue # ---- 一级标题双验证---- m1 r1.match(line) if m1: n, t m1.groups() if n in LEGAL and LEGAL[n] in line: node { number: n, title: LEGAL[n], content: , children: [] } root.append(node) curr1 node curr2 None continue # ---- 普通内容 ---- if curr2: curr2[content] line elif curr1: curr1[content] line return root # 打印结构 def show(tree): print(\n *80) print( 最终结构完美版) print(*80) for l1 in tree: print(f\n 1级 {l1[number]} {l1[title]}) for l2 in l1[children]: print(f ├─ 2级 {l2[number]} {l2[title]}) for l3 in l2[children]: print(f ├─ 3级 {l3[number]} {l3[content][:520]}) # 主函数 def main(): file rE:\pythonCode\DriveGenius\data\original\GB-4094汽车操纵件、指示器及信号装置的标志.docx out rE:\pythonCode\DriveGenius\data\outputs img_dir f{out}/GB4094 lines, doc load_doc(file) extract_images(doc, img_dir) root parse(lines) show(root) if input(\n生成 JSONy/n) y: with open(f{out}/GB4094.json, w, encodingutf-8) as f: json.dump({ 标准: GB4094-2016, 名称: 汽车操纵件、指示器及信号装置的标志, 内容: root }, f, ensure_asciiFalse, indent2) print(✅ 生成完成) if __name__ __main__: main()总体思路是通过分级标题1,1.2,2.3.1这种进行界定给每个区域都确定归属的文本块图片通过图注图XX单独提取并保存。演示运行结果如下正常提取出了结构随后点击确认正式产生对应的json文档。图片提取效果正常基本都正常提取到了没有切多或者切少了。《安全驾驶从这里开始》提取这是一本公安部于2013年出版的道路安全宣传小册子内容和驾驶员培训要求高度重合提取它作为知识库对于弥补上述材料中缺乏的信息源是十分有必要的可以看到该书还包含了上述其余文件没有包含的文明驾驶、特殊情况驾驶策略以及应急处理策略等方面的知识这些知识在实际考试中也占了很大的篇幅而且他的编写风格和题目也极其相似因此提取这方面的信息是十分有必要的。为简化工作量我们只提取了五六七三章的内容。关于提取方式由于书排版非常花里胡哨不仅有主线正文部分还有很多小插曲、小知识等。因此使用脚本进行完美提取几乎是不可能完成的。同样的我们参考之前提取GB5768的思路将这一过程利用LLM进行简化由它完成主要任务我们首先将要提取的章节进行PDF切分专门保存一份然后将它发给LLM并且说明我们的目的让它首先进行结构上的分析主要是进行标题的分层后面再利用现成的硬编码标题进行比对和提取强化它的理解记忆经过反馈纠正后最终确定的结构如下之后我们就按照这个结构让它有目的、有方向的进行提取在此之前我们还设计了一个提取的模板让它按照我们预想的结构进行提取均有三级标题三级标题下方若有显式分点就使用四级标题否则合并为内容只关注文字内容这样它就知道怎么提取、提取哪些、怎么返回等几个重要问题了通过适当的指令即可让它产生下面这样符合条件和要求的结果每次保持提取适当大小的上下文长度可以让它充分尊重原文原文、对非正文部分的表格等信息如各种受伤情况的救护措施表尽可能自然提取并且不覆盖正文这样逐个小节提取即可获得完整的知识库了图标知识库管理UI由于我们前期搜集的GB5768和GB4096的图标实际上并不完整需要后续补充为了方便补充我制作了一个图形化界面 用来管理这两类标志原理非常简单启动一个简易flask进程从json文件读取文字说明和路径并且找到相应的图片全部展示在页面上即可。除了检查图标和说明是否对应之外这个页面还支持上传新的图标、修改现有的图片有更好更清晰的话方便直接操作无需修改多个路径下文件。外观如下右上角点击新增条目可以传入图片实现增加图像会修改json脚本将标题和说明加入进去后期规划目前数据的收集和预处理以及基本完毕接下来计划的工作准备开始编写RAG查询接口将获取到的json文件和图像嵌入到向量数据库里面并完成底层的查询接口方法的实现。可以考虑做一个简易查询demo能够针对原始题目问题检索出来对应的法律条文/标志的官方解释含义。学习多数据源知识图谱的整合提取的方法要保证不同法律条令文本之间共有的实体能够在图数据库中共享一个节点做到多源异构信息的整合

相关文章:

2026春SDU软件创新实训第四周个人工作总结

第四周我做的工作总结如下: 从原始网页爬取科一科四题库 书接上期,我们找到了两个网页的题库(驾照吧(https://www.jiazhaoba.com/tiba)元贝驾考(https://www.ybjk.com/tiku))&…...

告别osgQt!用osgQOpenGLWidget在Qt6中轻松加载OsgEarth三维地球(附完整代码)

现代Qt6与OsgEarth集成实战:osgQOpenGLWidget替代方案详解 如果你正在使用Qt6开发三维地理可视化应用,却苦于找不到合适的OpenSceneGraph(OSG)集成方案,这篇文章将为你提供一条清晰的迁移路径。随着Qt和OSG版本的迭代,传统的osgQt…...

从CMIP6到SCI论文:气候降尺度全流程实战(含偏差校正与未来预估)-GCM数据降尺度、泰勒图评估及XGBoost机器学习建模指南

做水文气象、气候学、地理遥感、生态环境等领域的科研人&#xff0c;是不是都逃不过这些噩梦&#xff1a;尺度鸿沟难跨越&#xff1a;GCM 粗网格&#xff08;>100km&#xff09;和流域 / 城市精细尺度&#xff08;<10km&#xff09;不匹配&#xff0c;动力降尺度成本太高…...

Visio高效安装与激活全攻略:从零开始到成功运行

1. Visio安装前的准备工作 第一次安装Visio的朋友们&#xff0c;我强烈建议先做好这些准备工作。我自己在帮同事安装Visio时&#xff0c;经常遇到因为前期准备不足导致安装失败的情况。首先&#xff0c;检查你的电脑是否已经安装了其他版本的Office软件。如果之前安装过Office …...

2026.3.31 TRO成功和解案例 案件号:25-cv-25717,1000美金和解Palmer律所3000美金索赔,沃尔玛店铺全额解冻!

TRO经典案例案件概述案件号&#xff1a;25-cv-25717&#xff08;点击查看案件详情&#xff09;案件时间&#xff1a;2025-12-8收到TRO时间&#xff1a;2025-12-20销售平台&#xff1a;沃尔玛冻结金额&#xff1a;$209美金Palmer律所索赔额&#xff1a;$3,000美金侵权产品销售量…...

从v4l2-ctl命令到media拓扑:手把手教你调试RK3568上的OV8858摄像头图像

RK3568平台OV8858摄像头深度调试实战&#xff1a;从硬件链路到图像优化的全流程解析 当你在RK3568平台上调试OV8858摄像头时&#xff0c;是否遇到过这样的场景&#xff1a;设备树配置看似正确&#xff0c;但摄像头输出的图像却出现花屏、颜色异常或干脆没有信号&#xff1f;作为…...

CHORD-X构建自动化运维报告系统:服务器日志分析与日报生成

CHORD-X构建自动化运维报告系统&#xff1a;服务器日志分析与日报生成 最近和几个运维朋友聊天&#xff0c;发现他们每天都要花一两个小时写日报、周报。服务器状态、错误日志、性能趋势……这些数据分散在各个系统里&#xff0c;手动整理起来特别费劲。关键是&#xff0c;这种…...

文墨共鸣大模型入门指南:Ubuntu 20.04系统下的保姆级部署教程

文墨共鸣大模型入门指南&#xff1a;Ubuntu 20.04系统下的保姆级部署教程 想试试最近挺火的文墨共鸣大模型&#xff0c;但被复杂的部署步骤劝退了&#xff1f;别担心&#xff0c;这篇教程就是为你准备的。咱们今天不谈复杂的原理&#xff0c;就手把手教你&#xff0c;如何在Ub…...

Zotero中文文献管理终极指南:茉莉花插件一键解决三大痛点

Zotero中文文献管理终极指南&#xff1a;茉莉花插件一键解决三大痛点 【免费下载链接】jasminum A Zotero add-on to retrive CNKI meta data. 一个简单的Zotero 插件&#xff0c;用于识别中文元数据 项目地址: https://gitcode.com/gh_mirrors/ja/jasminum 如果你正在使…...

3个关键步骤:在电视盒子上完美运行Armbian系统的终极指南

3个关键步骤&#xff1a;在电视盒子上完美运行Armbian系统的终极指南 【免费下载链接】amlogic-s9xxx-armbian Supports running Armbian on Amlogic, Allwinner, and Rockchip devices. Support a311d, s922x, s905x3, s905x2, s912, s905d, s905x, s905w, s905, s905l, rk358…...

BUUCTF-[HITCON 2017]SSRFme

代码分析<?phpif (isset($_SERVER[HTTP_X_FORWARDED_FOR])) { //HTTP_X_FORWARDED_FOR可以获取客户端真正ip地址&#xff0c;和各个代理IP地址$http_x_headers explode(,, $_SERVER[HTTP_X_FORWARDED_FOR]); //拆分字符串&#xff0c;以&#xff0c;分割$_SERVER[REMOTE…...

数据宝藏库:Awesome Public Datasets完整入门指南

数据宝藏库&#xff1a;Awesome Public Datasets完整入门指南 【免费下载链接】awesome-public-datasets A topic-centric list of HQ open datasets. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-public-datasets 你是否曾经为了寻找高质量的数据集而烦…...

别再死磕理论了!用Python+Pytorch实战多示例学习(MIL)图像分类,附完整代码

用PythonPytorch实战多示例学习图像分类&#xff1a;从数据到模型的完整指南 当你第一次听说"多示例学习"&#xff08;Multiple Instance Learning, MIL&#xff09;时&#xff0c;是不是也被那些抽象的理论弄得一头雾水&#xff1f;作为计算机视觉领域的重要技术&am…...

避开这5个坑!用MediaRecorder+Vue3实现高兼容性语音输入

Vue3MediaRecorder实战&#xff1a;5个关键技巧打造高兼容语音输入方案 在移动优先的时代&#xff0c;语音输入已成为提升用户体验的重要交互方式。但当你兴奋地在Vue3项目中集成MediaRecorder API时&#xff0c;可能会遇到iOS设备上的静默失败、Android机型上的格式兼容性问题…...

Claude技能开发实战指南:从入门到精通的认知升级路径

Claude技能开发实战指南&#xff1a;从入门到精通的认知升级路径 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-…...

SQL 基础及 MySQL DBA 运维实战 - 6:Mycat代理技术

MySQL DBA运维实战&#xff1a;集群与代理技术深度解析 引言 在现代互联网应用中&#xff0c;数据库的高可用性、可扩展性和性能是企业级应用的核心需求。随着业务量的增长&#xff0c;单一数据库服务器往往无法满足需求&#xff0c;此时数据库集群和代理技术成为解决这些问题…...

实战应用:使用快马平台为vmware17部署生成企业级健康检查与配置方案

在实际的企业IT环境中&#xff0c;部署VMware vSphere 17&#xff08;以下简称VMware 17&#xff09;这类虚拟化平台往往不是简单的安装过程&#xff0c;而是需要综合考虑硬件兼容性、系统配置、安全策略等多方面因素。为了确保部署过程的顺利和后续运行的稳定&#xff0c;我们…...

AI赋能开发:让快马平台智能理解并生成产区标准图交互应用

AI赋能开发&#xff1a;让快马平台智能理解并生成产区标准图交互应用 最近在做一个农产品产区标准查询系统的项目&#xff0c;发现用传统方式开发这类需求特别费时。比如要处理用户自然语言查询、动态生成地图、实现智能推荐逻辑&#xff0c;光写基础代码就得花好几天。后来尝…...

新手必看:在快马平台学习排列组合公式的代码实现

新手必看&#xff1a;在快马平台学习排列组合公式的代码实现 作为一个编程新手&#xff0c;当我第一次接触排列组合公式时&#xff0c;那些数学符号和递归逻辑让我一头雾水。直到在InsCode(快马)平台上找到了带详细注释的示例代码&#xff0c;才真正理解了Cn和An公式的实现原理…...

赋能音乐自由:Unlock Music技术解密与全场景应用指南

赋能音乐自由&#xff1a;Unlock Music技术解密与全场景应用指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: https:…...

告别重复造轮子:用快马AI一键生成高复用性imToken集成代码模块

告别重复造轮子&#xff1a;用快马AI一键生成高复用性imToken集成代码模块 开发涉及钱包集成的DApp时&#xff0c;最让人头疼的就是那些重复性的基础代码。每次新项目都要重新写一遍连接钱包、处理授权、监听网络切换的逻辑&#xff0c;不仅浪费时间&#xff0c;还容易引入安全…...

终极窗口尺寸编辑器:SRWE让你的应用程序窗口自由伸缩

终极窗口尺寸编辑器&#xff1a;SRWE让你的应用程序窗口自由伸缩 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE Simple Runtime Window Editor (SRWE) 是一款革命性的开源工具&#xff0c;它能让你实时调整任何…...

音乐标签编辑器:让本地音乐元数据管理效率提升90%的开源工具

音乐标签编辑器&#xff1a;让本地音乐元数据管理效率提升90%的开源工具 【免费下载链接】music-tag-web 音乐标签编辑器&#xff0c;可编辑本地音乐文件的元数据&#xff08;Editable local music file metadata.&#xff09; 项目地址: https://gitcode.com/gh_mirrors/mu/…...

FanControl完全指南:5分钟掌握Windows风扇智能控制

FanControl完全指南&#xff1a;5分钟掌握Windows风扇智能控制 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/Fa…...

如何用3dsconv解决3DS游戏格式兼容问题:从入门到精通的转换指南

如何用3dsconv解决3DS游戏格式兼容问题&#xff1a;从入门到精通的转换指南 【免费下载链接】3dsconv Python script to convert Nintendo 3DS CCI (".cci", ".3ds") files to the CIA format 项目地址: https://gitcode.com/gh_mirrors/3d/3dsconv …...

M2LOrder模型在STM32项目中的潜在应用:边缘设备情绪反馈

M2LOrder模型在STM32项目中的潜在应用&#xff1a;边缘设备情绪反馈 最近在捣鼓一个基于STM32的智能硬件项目&#xff0c;想给它加点“人情味”。比如&#xff0c;当用户对它说话时&#xff0c;它能感知到用户的情绪是开心还是沮丧&#xff0c;并给出更贴切的反馈。这听起来很…...

Audio2Face深度解析:音频驱动面部动画的技术架构与实战指南

Audio2Face深度解析&#xff1a;音频驱动面部动画的技术架构与实战指南 【免费下载链接】FACEGOOD-Audio2Face http://www.facegood.cc 项目地址: https://gitcode.com/gh_mirrors/fa/FACEGOOD-Audio2Face 在虚拟数字人快速发展的今天&#xff0c;如何让虚拟角色拥有自然…...

安卓应用按钮样式问题及解决方案

在开发安卓应用的过程中,我们常常会遇到一些看似简单但实际上隐藏着复杂问题的样式问题。今天我们来探讨一个在更换设备后按钮样式发生变化的问题。 问题描述 一位开发者在Android Studio中开发了一个食谱应用。当他从一台手机切换到另一台手机运行应用时,发现所有的按钮都…...

Sketch Measure: 设计标注自动化的创新实践

Sketch Measure: 设计标注自动化的创新实践 【免费下载链接】sketch-measure Make it a fun to create spec for developers and teammates 项目地址: https://gitcode.com/gh_mirrors/sk/sketch-measure 在数字化产品开发流程中&#xff0c;设计稿到代码实现的转化始终…...

如何使用usearch构建精准视频内容推荐系统:基于观看历史的向量匹配方案

如何使用usearch构建精准视频内容推荐系统&#xff1a;基于观看历史的向量匹配方案 【免费下载链接】usearch Fast Open-Source Search & Clustering engine for Vectors & Arbitrary Objects in C, C, Python, JavaScript, Rust, Java, Objective-C, Swift, C#, GoL…...