知识图谱建立以及基于图谱的知识问答实战——以古诗文知识为例

最近比赛需要,所以特出一期建立知识图谱和相关知识问答的教程
整个过程需要用到工具Neo4j,这在我以前的博客中讲到怎么部署详情请看:
Neo4j部署教程

如果想快速入门Neo4j请点击这里:
Neo4j快速入门

此项目的github地址

参考的刘焕勇项目地址

一. 构建数据集

最终的数据格式:

{
   "name":"八阵图","author":"杜甫","dynasty":"唐","category":"五言绝句","content":"功盖三分国,名成八阵图。(名成 一作:名高)江流石不转,遗恨失吞吴。","trans":"三国鼎立你建立了盖世功绩,创八阵图你成就了永久声名。任凭江流冲击,石头却依然如故,遗憾的是刘备不听诸葛亮之言吞吴失策。","annotation":"八阵图:由八种阵势组成的图形,用来操练军队或作战。盖:超过。三分国:指三国时魏、蜀、吴三国。石不转:指涨水时,八阵图的石块仍然不动。失吞吴:是吞吴失策的意思。","background":"杜甫在公元766年(唐代宗大历元年)夏迁居夔州,夔州有武侯庙,江边有八阵图,传说为三国时诸葛亮在夔州江滩所设。向来景仰诸葛亮的杜甫用了许多笔墨记咏古迹抒发情怀。《八阵图》便是其中一首。","appreciation":"这是作者初到夔州(治今重庆奉节)时的一首咏怀诸葛亮的诗,写于大历元年(766)。“八阵图”,指由天、地、风、云、龙、虎、鸟、蛇八种阵势所组成的军事操练和作战的阵图,由诸葛亮创制而成,反映了他卓越的军事才能。“功盖三分国,名成八阵图。”这首小诗的前两句是说,三国鼎立你建立了盖世功绩,创八阵图你成就了永久声名。这两句赞颂了诸葛亮的丰功伟绩。第一句是从总的方面来写,说诸葛亮在确立魏蜀吴三分天下、鼎足而立的局势的过程中,功绩最为卓绝。三国并存局面的形成,固然有许多因素,而诸葛亮辅助刘备从无到有的创建蜀国基业,应该说是重要原因之一。杜甫这一高度概括的赞语,客观地反映了三国时代的历史真实。第二句是从具体的方面来说,诸葛亮创制的八阵图使他声名卓著。对这一点古人曾屡加称颂,而杜甫的这句诗则是更集中、更凝练的赞颂了诸葛亮的军事业绩。这两句诗在写法上用的是对仗句,“三分国”对“八阵图”,以全局性的业绩对军事上的贡献,显得精巧工整,自然妥帖。在结构上,前句劈头提起,开门见山;后句点出诗题,进一步赞颂功绩,同时又为下面凭吊遗迹做了铺垫。“江流石不转,遗恨失吞吴。”这两句就“八阵图”的遗址抒发感慨。“八阵图”遗址在夔州西南永安宫前平沙上。据《荆州图副》和刘禹锡《嘉话录》记载,这里的八阵图聚细石成堆,高五尺,六十围,纵横棋布,排列为六十四堆,始终保持原来的样子不变,即使被夏天大水冲击淹没,等到冬季水落平川,万物都失故态,唯独八阵图的石堆却依然如旧,六百年来岿然不动。前一句极精炼地写出了遗迹这一富有神奇色彩的特征。“石不转”,化用了《诗经·国风·邶风·柏舟》中的诗句“我心匪石,不可转也”。在作者看来,这种神奇色彩和诸葛亮的精神心志有内在的联系:他对蜀汉政权和统一大业忠贞不二,矢志不移,如磐石之不可动摇。同时,这散而复聚、长年不变的八阵图石堆的存在,似乎又是诸葛亮对自己赍志以殁表示惋惜、遗憾的象征,所以杜甫紧接着写的最后一句是“遗恨失吞吴”,说刘备吞吴失计,破坏了诸葛亮联吴抗曹的根本策略,以致统一大业中途夭折,而成了千古遗恨。当然,这首诗与其说是在写诸葛亮的“遗恨”,无宁说是杜甫在为诸葛亮惋惜,并在这种惋惜之中渗透了杜甫“伤己垂暮无成”(黄生语)的抑郁情怀。这首怀古绝句,具有融议论入诗的特点。但这种议论并不空洞抽象,而是语言生动形象,抒情色彩浓郁。诗人把怀古和述怀融为一体,浑然不分,给人一种此恨绵绵、余意不尽的感觉。"}

要想做到这一点,爬虫是必不可少的!
爬虫代码如下:

import requests
from bs4 import BeautifulSoup


def fetch_html(url):
    try:
        response = requests.get(url)
        response.raise_for_status()
        return response.text
    except requests.RequestException as e:
        print(f"Error fetching HTML content: {
     e}")
        return None


def extract_poem_urls(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    poem_urls = []

    for a_tag in soup.find_all('a', href=True):
        href = a_tag['href']
        if href.startswith("/shiwenv_"):
            full_url = f"https://so.gushiwen.cn{
     href}"
            poem_urls.append(full_url)

    return poem_urls


def fetch_poem_details(url):
    poem_details = {
   
        "name": "",
        "author": "",
        "dynasty": "",
        "content": "",
        "trans": "",
        "annotation": "",
        "appreciation": "",
        "background": ""
    }
    response = requests.get(url)
    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')

        title_tag = soup.find('h1')
        if title_tag:
            poem_details["name"] = title_tag.text.strip().replace("\n", "")

        source_tag = soup.find('p', class_='source')
        if source_tag:
            source_info = source_tag.find_all('a')
            if len(source_info) > 0:
                poem_details["author"] = source_info[0].text.strip().replace("\n", "")
                poem_details["dynasty"] = source_info[1].text.strip().replace("\n", "").replace("〔", "").replace("〕",
                                                                                                                 "")

        content_tag = soup.find('div', class_='contson')
        if content_tag:
            poem_details["content"] = content_tag.get_text().strip().replace("\n", "")

        # 提取译文和注释
        trans_annotation_tag = soup.find('div', class_='contyishang')
        if trans_annotation_tag:
            p_tags = trans_annotation_tag.find_all('p')
            for p_tag in p_tags:
                if '译文' in p_tag.text:
                    poem_details["trans"] = p_tag.get_text().strip().replace("译文", "").replace("展开阅读全文 ∨", "")
                elif '注释' in p_tag.text:
                    poem_details["annotation"] = p_tag.get_text().strip().replace("注释", "").replace("展开阅读全文 ∨", "")

        appreciation_divs = soup.find_all('div', class_='contyishang')
        for div in appreciation_divs:
            if div.find('h2') and ('赏析' in div.find('h2').text or '鉴赏' in div.find('h2').text):
                appreciation_paragraphs = div.find_all('p')
                appreciation_text = "".join(p.get_text().strip() for p in appreciation_paragraphs).replace("\n", "").replace("展开阅读全文 ∨", "")
                poem_details["appreciation"] += "。"+appreciation_text

        # 提取创作背景
        background_divs = soup.find_all('div', class_='contyishang')
        for div in background_divs:
            if div.find('h2') and '创作背景' in div.find('h2').text:
                background_paragraphs = div.find_all('p')
                background_text = "".join(p.get_text().strip() for p in background_paragraphs).replace("\n", "").replace("展开阅读全文 ∨", "")
                poem_details["background"] = background_text

    return poem_details


if __name__ == "__main__":
    urls = [
        "https://so.gushiwen.cn/gushi/tangshi.aspx",
        "https://so.gushiwen.cn/gushi/sanbai.aspx",
        "https://so.gushiwen.cn/gushi/songsan.aspx"
    ]

    poem_urls = []
    for url in urls:
        html_content = fetch_html(url)
        if html_content:
            poem_urls.extend(extract_poem_urls(html_content))
        else:
            print("Failed to fetch or parse HTML content.")

    for url in poem_urls:
        details = fetch_poem_details(url)
        print(details)

整理成上面描述的json格式后我们便可以进行下一步。

二. 代码设计

2.1 构建知识图谱

该项功能由build_graph.py来实现,具体代码如下:

import os
from py2neo import Graph,Node
import json

class KL_Graph(
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光诺言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值