编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

对知识库Wikidata的爬虫以及将三元组关系语料库获取知识图谱数据

wxchong 2024-08-08 00:55:32 开源技术 44 ℃ 0 评论


项目地址:

https://github.com/CrisJk/Agriculture-KnowledgeGraph-Data.git


说明

本项目为一些用于获取知识图谱中三元组关系的python脚本。包括爬取Wikidata数据的爬虫、爬取复旦知识工场数据的爬虫(由于知识工场限制爬取,这部分暂时不好用)、提取所有中文维基页面的脚本以及将Wikidata三元组数据对齐到中文维基页面语句的脚本。

运行环境

python3、 Scrapy、neo4j(仅对齐时需要)

wikidataCrawler

用来爬取wikidata上定义的所有关系

wikidata中的所有关系都汇总在该网页上(链接) ,wikidataCrawler将该网页下的汇总的所有关系及其对应的中文名称爬取下来,存储为json格式

使用方法

进入到wikidataCrawler目录下,运行scrapy crawl relation即可爬取wikidata中定义的所有关系。可以得到relation.jsonchrmention.json

  • relation.json内容: 关系的id,关系所属的大类,关系所属子类,对应的链接,关系的英文表示

  • chrmention.json内容: 关系的id,关系的中文表示(对于不包含中文表示的数据暂时不做处理)。

relation.jsonchrmention.json的数据进行合并,运行mergeChrmentionToRelation.ipynb即可,得到的结果存储在result.json中,匹配失败的存在fail.json

wikientities

用来爬取实体,返回json格式

进入到wikientities目录下,运行scrapy crawl entity。可以得到 entity.json

entity.json 是以predict_labels.txt中的实体为搜索词,在wikidata上搜索返回的json内容。

entity.json中还包括搜索词(即实体)以及实体所属的类别(和predict_labels.txt中一样)也加入json中存储。

由于我目前想做一个农业领域的知识图谱,因此predict_label.txt中很多词都是关于农业的,若想爬取其他实体,则自己修改predict_label.txt中的数据即可。

wikidataRelation说明

用来爬取实体和实体间的关系三元组,返回三元组

Wikidata是一个开放的全领域的知识库,其中包含大量的实体以及实体间的关系。下图是一个wikidata的实体页面

从图中可以看到wikidata实体页面包含实体的描述和与该实体相关联的其它实体及对应的关系。

wikidataRelation爬取得到的是实体和实体间的三元关系,例如合成橡胶石油之间存在material used的关系,因此可以得到如下json格式的三元组:

{"entity1": "合成橡胶", "relation": "material used", "entity2": "石油"}

使用方法

首先运行preProcess.py,得到readytoCrawl.json。然后进入到wikidataRelation目录下,运行scrapy crawl entityRelation。可以得到entityRelation.json

entityRelation.json是利用entity.json中的所有实体为基础,获取与这些实体相关的其他实体和关系。

wikidataProcessing

用来处理得到的三元组关系(entityRelation.json)

将得到的entityRelation.json 处理成csv,并且存入neo4j数据库。该文件夹下的两个文件hudong_pedia.csv hudong_pedia2.csv 是爬取互动百科相关页面得到的,对应的就是wikientities目录下的predict_label.txt中的实体。运行relationDataProcessing.py 可以得到new_node.csv (即从wikidata实体页面中爬取得到的实体不包含在predict_label.txt中的部分)、wikidata_relation.csv(predict_label.txt中实体之间的关系)以及wikidata_relation2.csv(predict_label.txt中实体和新发现实体间的关系),将该目录下所有csv导入到neo4j中,具体操作参见Agriculture_KnowledgeGraph 中的项目部署部分。

CN_DBpediaCrawler

CN_DBpedia限制访问,需要向复旦大学知识工场申请API,否则只能限制每分钟爬取次数,这里的爬虫还有些问题,暂时不能使用。

wikiextractor

wikiextractor是用来获取维基百科语料的工具,维基百科有wiki dump可以直接下载:下载链接 ,下载好之后,利用wikiextractor工具进行处理,可以剔除掉一些无用的信息,直接得到维基百科语料库。wikiextractor工具链接 ,下载并安装后,将wiki dump放在wikiextractor目录下,执行命令

bzcat zhwiki-latest-pages-articles.xml.bz2 | python WikiExtractor.py -b 500K -o extracted -

可以得到处理好的维基百科语料,在目录extractor下。

由于得到的语料既有简体也有繁体,所以要进行繁简体转换。将本项目wikiextractor\extracted目录下的三个python文件复制到你处理好的维基百科语料的目录(extractor)下,运行convLan.py便可以将繁体转化为简体。

TrainDataBaseOnWiki

用于将从wikidata知识库中获取的三元组关系对齐到中文维基的语料库上

首先必须将wikidataProcessing目录下的csv导入到neo4j中,才能成功运行。运行extractTrainingData.py后,可以得到train_data.txt ,其内容包含:

entity1entity2statementrelation

得到train_data.txt后,使用dataScrubbing.py处理得到的数据,包括:

  • 错误处理

    部分句子有换行,把换行去掉

    第一次产生的数据train_data.txt,由于之前程序在切割字符串时出了问题,因此relation这一列不对,这里重新处理一下

  • 选择农业相关的数据

    从所有训练集中挑选出与农业有关的数据

运行

python dataScrubbing.py handleError

执行错误管理模块

运行

python dataScrubbing.py selectAgriculturalData

执行数据选择模块



主要代码:

# -*- coding: utf-8 -*-

2

3 # Define here the models for your spider middleware

4 #

5 # See documentation in:

6 # http://doc.scrapy.org/en/latest/topics/spider-middleware.html

7

8 from scrapy import signals

9

10

11 class WikidatacrawlerSpiderMiddleware(object):

12 # Not all methods need to be defined. If a method is not defined,

13 # scrapy acts as if the spider middleware does not modify the

14 # passed objects.

15

16 @classmethod

17 def from_crawler(cls, crawler):

18 # This method is used by Scrapy to create your spiders.

19 s = cls()

20 crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)

21 return s

22

23 def process_spider_input(self, response, spider):

24 # Called for each response that goes through the spider

25 # middleware and into the spider.

26

27 # Should return None or raise an exception.

28 return None

29

30 def process_spider_output(self, response, result, spider):

31 # Called with the results returned from the Spider, after

32 # it has processed the response.

33

34 # Must return an iterable of Request, dict or Item objects.

35 for i in result:

36 yield i

37

38 def process_spider_exception(self, response, exception, spider):

39 # Called when a spider or process_spider_input() method

40 # (from other spider middleware) raises an exception.

41

42 # Should return either None or an iterable of Response, dict

43 # or Item objects.

44 pass

45

46 def process_start_requests(self, start_requests, spider):

47 # Called with the start requests of the spider, and works

48 # similarly to the process_spider_output() method, except

49 # that it doesn’t have a response associated.

50

51 # Must return only requests (not items).

52 for r in start_requests:

53 yield r

54

55 def spider_opened(self, spider):

56 spider.logger.info('Spider opened: %s' % spider.name)


import scrapy

2 import time

3 import re

4 from wikidataCrawler.items import WikidatacrawlerItem

5 from scrapy_splash import SplashRequest

6 class relationSpider(scrapy.spiders.Spider):

7 name = "relation"

8 allowed_domains = ["wikidata.org"]

9 start_urls = [

10 "https://www.wikidata.org/wiki/Wikidata:List_of_properties/Summary_table"

11

12 ]

13 def parse(self , response):

14 count = 0

15 rcount = 0

16 relationItem_list = list()

17 relationType = list()

18 link_list = list()

19 rtype_list = list()

20 for headline in response.xpath('//span[contains(@class,"mw-headline")]'):

21 rtype = re.sub("[^A-Za-z]","",headline.xpath('.//text()').extract()[0])

22 rtype_list.append(rtype)

23 table_number_list = [5,7,9,2,14,20,13,5]

24 rcount = 1

25 rrcount = 0

26 rrrcount = 0

27 for table in response.xpath('//table[contains(@class,"wikitable")]'):

28 rsubtype = re.sub("[^A-Za-z\s]","",table.xpath('.//th/text()').extract()[0])

29 for li in table.xpath('.//li/a'):

30 relationId = li.xpath('./small/text()').extract()[0]

31 relationId = re.sub("[^A-Za-z0-9]","",relationId)

32 link = li.xpath('./@href').extract()[0]

33 link = re.sub("[[]\']","",link)

34 link = "https://www.wikidata.org"+link

35 link_list.append(link)

36 rmention = li.xpath('.//text()').extract()[0]

37 rmention = re.sub("[^A-za-z0-9\s]","",rmention)

38 if((rtype_list[rcount] == 'Organization' and rsubtype == 'Generic') or(rtype_list[rcount] == 'Works' and rsubtype == 'Film')):

39 continue

40 tmp =WikidatacrawlerItem()

41 relationItem_list.append(WikidatacrawlerItem())

42 relationItem_list[count]['rid'] = relationId

43 relationItem_list[count]['rtype'] = rtype_list[rcount]

44 relationItem_list[count]['rsubtype'] = rsubtype

45 relationItem_list[count]['link'] = link

46 relationItem_list[count]['rmention'] = rmention

47 yield relationItem_list[count]

48 count+=1

49 rrrcount += 1

50 if(rrrcount == table_number_list[rrcount] ):

51 rrrcount = 0

52 rrcount += 1

53 rcount += 1

54

55 print('number of relation types is %d' %count)

56 splash_args = {

57 'wait': 0.5,

58 }

59 for url in link_list:

60 chrelationItem = WikidatacrawlerItem()

61 request = scrapy.Request(url, callback=self.parse_relation_pages)

62 request.meta['item'] = chrelationItem

63 rid = url.split(":")[2]

64 request.meta['rid'] = rid

65 yield request

66

67

68

69 def parse_relation_pages(self , response):

70 chrelationItem = response.meta['item']

71 chrelationItem['rid'] = response.meta['rid']

72 zh_pattern = re.compile(r'\\\"language\\\":\\\"zh\\\",\\\"value\\\":\\\"(.*?)\\\"')

73 zhhans_pattern = re.compile(r'\\\"language\\\":\\\"zh-hans\\\",\\\"value\\\":\\\"(.*?)\\\"')

74 for script in response.xpath('//script').extract():

75 zh = re.findall(zh_pattern,script)

76 if(len(zh)>0):

77 zh[0] = re.sub(r'\\\\',r'\\',zh[0])

78 chrelationItem['chrmention'] = zh[0].encode('latin-1').decode('unicode_escape')

79 break;

80

81 else:

82 zh_hans = re.findall(zhhans_pattern,script)

83 if(len(zh_hans) > 0 ):

84

85 zh_hans[0] = re.sub(r'\\\\',r'\\',zh_hans[0])

86 chrelationItem['chrmention'] = zh_hans[0].encode('latin-1').decode('unicode_escape')

87 break;

88 else:

89 chrelationItem['chrmention'] = "no chinese label"

90 return chrelationItem



Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表