抓取维基百科数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/npf_java/article/details/50196131

1方案概述

抓取维基百科数据。

根据网上调查,现有三种解决方案:

²  使用Apache Nutch爬虫技术,深度抓取页面数据。

²  使用JWPL技术,解析Wikipaia离线数据。

²  使用Jsoup工具类,解析Wikipaia在线html dom元素。

2方案分析

2.1 ApacheNutch

2.1 Apache Nutch

2.1.1原理

Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。

1. 创建一个新的WebDb (admin db -create).

2. 将抓取起始URLs写入WebDB (inject).

3. 根据WebDB生成fetchlist并写入相应的segment(generate).

4. 根据fetchlist中的URL抓取网页 (fetch).

5. 根据抓取网页更新WebDb (updatedb).

扫描二维码关注公众号,回复: 3113740 查看本文章

6. 循环进行35步直至预先设定的抓取深度。

7. 根据WebDB得到的网页评分和links更新segments (updatesegs).

8. 对所抓取的网页进行索引(index).

9. 在索引中丢弃有重复内容的网页和重复的URLs (dedup).

10. segments中的索引进行合并生成用于检索的最终index(merge).

 

2.1.2不足

Nutch可以广度的抓取html页面,但是不能精确的分析html页面元素,进行数据分析。

2.2 JWPL

2.2.1原理

JWPL(Java Wikipedia Library)是一个开源的访问wikipeida数据的java api包。它提供的DataMachine 工具类可快速解析wiki格式文件,生成mysql的数据txt文件,可通过mysqlimport 导入到本地数据库中

2.2.2不足

无法快速有效的从词条正文(wiki格式的数据)中提取有用的信息,需要解析比对wiki中的数据模板,来查找对应的属性

2.3 Jsoup

2.3.1原理

Jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

2.3.2不足

只能解析制定url的html页面信息,无法像Nutch 一样自动的进行页面抓取。

3方案实施

3.1 结论

通过以上的方案分析,任何单独的一种技术都无法实现 精确抓取维基百科数据的功能。但是可以利用这些技术的优点,进行组合查询。

l  利用JWPL技术将下载的wikipedia数据进行解析,存入本地的mysql数据库中。然后根据表之间的关系,遍历分类信息,最后根据分类信息查询对应的词条。

²  Category 分类信息表

²  Category_outlinks 分类信息和父节点关系表

²  Category_pages 分类信息对应词条表

²  Page 词条信息表

l  词条信息 = https://zh.wikipedia.org/wiki/ + 词条名称

l  根据Jsoup技术解析 url 获取html信息,找出对应的属性、概述、文本

3.2 步骤

3.2.1Jwpl解析wiki数据

l  指导性的文章  

 http://www.cs.bgu.ac.il/~elhadad/nlp12/jwpl/wikification.html

http://www.cnblogs.com/heshizhu/archive/2012/06/26/2564267.html

3.2.1.1下载维基百科 历史数据

中文维基 历史下载地址http://dumps.wikimedia.org/zhwiki/

 需下载这三个 压缩包

 http://download.wikipedia.com/zhwiki/20150703/zhwiki-20150703-pages-articles.xml.bz2

 http://download.wikipedia.com/zhwiki/20150703/zhwiki-20150703-categorylinks.sql.gz

 http://download.wikipedia.com/zhwiki/20150703/zhwiki-20150703-pagelinks.sql.gz

3.2.1.2下载Wikipedia离线阅读器WikiTaxi

http://jingyan.baidu.com/article/90895e0fb9fb5164ec6b0b1e.html

3.2.1.3下载JWPL jar

下载 DataMachine地址:

https://repo1.maven.org/maven2/de/tudarmstadt/ukp/wikipedia/de.tudarmstadt.ukp.wikipedia.datamachine/0.9.1/de.tudarmstadt.ukp.wikipedia.datamachine-0.9.1-jar-with-dependencies.jar

下载 WikipediaAPI 地址:

https://repo1.maven.org/maven2/de/tudarmstadt/ukp/wikipedia/de.tudarmstadt.ukp.wikipedia.api/0.9.1/de.tudarmstadt.ukp.wikipedia.api-0.9.1-jar-with-dependencies.jar

3.2.1.4通过JWPL 中的DataMachine 工具 解析下载的历史数据


   
   
java -jar JWPLDataMachine.jar [LANGUAGE][MAIN_CATEGORY_NAME][DISAMBIGUATION_CATEGORY_NAME][SOURCE_DIRECTORY]

LANGUAGE——JWPL_Languages语言字符串匹配。

MAIN_CATEGORY_NAME——主要的名称(上)类别的Wikipedia类别层次结构

DISAMBIGUATION_CATEGORY_NAME -类别的名称包含消歧的类别

SOURCE_DIRECTORY——包含源文件的目录的路径

l  本机命令:

   
   
D:\Wikipedia>java -Dfile.encoding=utf8 -Xmx4g-cp jar-with-dependencies.jar de.t
 
udarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine chinese 頁面分類消歧义./zhwiki
DataMachine需要运行很长时间。运行完会在SOURCE_DIRECTORY目录下生成一个output目录,该目录里面有11个文件,这11个文件就是需要导入到mysql中的结构化数据了

3.2.1.5将解析完成的 txt文件导入到mysql数据库中

3.2.1.5.1创建数据库
   
   
CREATE DATABASE zhwiki DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
3.2.1.5.2执行建表sql

jwpl_tables.sql  http://www.cs.bgu.ac.il/~elhadad/nlp12/jwpl/jwpl_tables.sql

   
   
--MySQLdump10.11
--
--Host: localhost Database: jwpl_tables
--------------------------------------------------------
--Server version 5.0.37-community-nt
 
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
 
--
--Table structure for table `Category`
--
 
DROP TABLE IF EXISTS `Category`;
CREATE TABLE `Category`(
`id` bigint(20) NOT NULL auto_increment,
`pageId`int(11)default NULL,
`name` varchar(255)default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `pageId`(`pageId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `Category`
--
 
LOCK TABLES `Category` WRITE;
/*!40000 ALTER TABLE `Category` DISABLE KEYS */;
/*!40000 ALTER TABLE `Category` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `category_inlinks`
--
 
DROP TABLE IF EXISTS `category_inlinks`;
CREATE TABLE `category_inlinks`(
`id` bigint(20) NOT NULL,
`inLinks`int(11)default NULL,
KEY `FK3F433773E46A97CC`(`id`),
KEY `FK3F433773BB482769`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `category_inlinks`
--
 
LOCK TABLES `category_inlinks` WRITE;
/*!40000 ALTER TABLE `category_inlinks` DISABLE KEYS */;
/*!40000 ALTER TABLE `category_inlinks` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `category_outlinks`
--
 
DROP TABLE IF EXISTS `category_outlinks`;
CREATE TABLE `category_outlinks`(
`id` bigint(20) NOT NULL,
`outLinks`int(11)default NULL,
KEY `FK9885334CE46A97CC`(`id`),
KEY `FK9885334CBB482769`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `category_outlinks`
--
 
LOCK TABLES `category_outlinks` WRITE;
/*!40000 ALTER TABLE `category_outlinks` DISABLE KEYS */;
/*!40000 ALTER TABLE `category_outlinks` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `category_pages`
--
 
DROP TABLE IF EXISTS `category_pages`;
CREATE TABLE `category_pages`(
`id` bigint(20) NOT NULL,
`pages`int(11)default NULL,
KEY `FK71E8D943E46A97CC`(`id`),
KEY `FK71E8D943BB482769`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `category_pages`
--
 
LOCK TABLES `category_pages` WRITE;
/*!40000 ALTER TABLE `category_pages` DISABLE KEYS */;
/*!40000 ALTER TABLE `category_pages` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `MetaData`
--
 
DROP TABLE IF EXISTS `MetaData`;
CREATE TABLE `MetaData`(
`id` bigint(20) NOT NULL auto_increment,
`language` varchar(255)default NULL,
`disambiguationCategory` varchar(255)default NULL,
`mainCategory` varchar(255)default NULL,
`nrofPages` bigint(20)default NULL,
`nrofRedirects` bigint(20)default NULL,
`nrofDisambiguationPages` bigint(20)default NULL,
`nrofCategories` bigint(20)default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `MetaData`
--
 
LOCK TABLES `MetaData` WRITE;
/*!40000 ALTER TABLE `MetaData` DISABLE KEYS */;
/*!40000 ALTER TABLE `MetaData` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `Page`
--
 
DROP TABLE IF EXISTS `Page`;
CREATE TABLE `Page`(
`id` bigint(20) NOT NULL auto_increment,
`pageId`int(11)default NULL,
`name` varchar(255)default NULL,
`text` longtext,
`isDisambiguation` bit(1)default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `pageId`(`pageId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `Page`
--
 
LOCK TABLES `Page` WRITE;
/*!40000 ALTER TABLE `Page` DISABLE KEYS */;
/*!40000 ALTER TABLE `Page` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `page_categories`
--
 
DROP TABLE IF EXISTS `page_categories`;
CREATE TABLE `page_categories`(
`id` bigint(20) NOT NULL,
`pages`int(11)default NULL,
KEY `FK72FB59CC1E350EDD`(`id`),
KEY `FK72FB59CC75DCF4FA`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `page_categories`
--
 
LOCK TABLES `page_categories` WRITE;
/*!40000 ALTER TABLE `page_categories` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_categories` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `page_inlinks`
--
 
DROP TABLE IF EXISTS `page_inlinks`;
CREATE TABLE `page_inlinks`(
`id` bigint(20) NOT NULL,
`inLinks`int(11)default NULL,
KEY `FK91C2BC041E350EDD`(`id`),
KEY `FK91C2BC0475DCF4FA`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `page_inlinks`
--
 
LOCK TABLES `page_inlinks` WRITE;
/*!40000 ALTER TABLE `page_inlinks` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_inlinks` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `page_outlinks`
--
 
DROP TABLE IF EXISTS `page_outlinks`;
CREATE TABLE `page_outlinks`(
`id` bigint(20) NOT NULL,
`outLinks`int(11)default NULL,
KEY `FK95F640DB1E350EDD`(`id`),
KEY `FK95F640DB75DCF4FA`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `page_outlinks`
--
 
LOCK TABLES `page_outlinks` WRITE;
/*!40000 ALTER TABLE `page_outlinks` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_outlinks` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `page_redirects`
--
 
DROP TABLE IF EXISTS `page_redirects`;
CREATE TABLE `page_redirects`(
`id` bigint(20) NOT NULL,
`redirects` varchar(255)default NULL,
KEY `FK1484BA671E350EDD`(`id`),
KEY `FK1484BA6775DCF4FA`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `page_redirects`
--
 
LOCK TABLES `page_redirects` WRITE;
/*!40000 ALTER TABLE `page_redirects` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_redirects` ENABLE KEYS */;
UNLOCK TABLES;
 
--
--Table structure for table `PageMapLine`
--
 
DROP TABLE IF EXISTS `PageMapLine`;
CREATE TABLE `PageMapLine`(
`id` bigint(20) NOT NULL auto_increment,
`name` varchar(255)default NULL,
`pageID`int(11)default NULL,
`stem` varchar(255)default NULL,
`lemma` varchar(255)default NULL,
PRIMARY KEY (`id`),
KEY `name`(`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--
--Dumping data for table `PageMapLine`
--
 
LOCK TABLES `PageMapLine` WRITE;
/*!40000 ALTER TABLE `PageMapLine` DISABLE KEYS */;
/*!40000 ALTER TABLE `PageMapLine` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
 
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
 
--Dump completed on 2008-02-1112:33:30

3.2.1.5.3导入数据库

在output目录下执行批处理文件 dbimport.bat:

   
   
@echo off
 
set db=zhwiki
 
set usr=root
 
set pwd=root
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db%Category.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% category_inlinks.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% category_outlinks.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% category_pages.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db%MetaData.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db%Page.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db%PageMapLine.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% page_categories.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% page_inlinks.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% page_outlinks.txt
 
mysqlimport -u%usr%-p%pwd%--local--default-character-set=utf8 %db% page_redirects.txt
 

3.2.2Jsoup解析hml

   
   
/**
 
* 利用Jsoup技术解析html
 
*/
 
privatevoidJsoupHtml(String categoryId,String entryId,String name){
 
Date date =newDate();
 
//中文 简体转繁体 工具类
 
ZHConverter converter =ZHConverter.getInstance(ZHConverter.SIMPLIFIED);
 
 
String url ="https://zh.wikipedia.org/wiki/"+name;
 
name = converter.convert(name);
 
Long sTime =System.currentTimeMillis();
 
logger.info(name+" --------------------------------------------解析开始:---------------------------------url--"+url);
 
//判断数据库中是否存在该词条
 
String queryEntryByNameSql ="select t.id from bk_entry t where t.name = '"+name+"'";
 
List<Map<String,Object>> list =newArrayList<Map<String,Object>>();
 
try{
 
list = jtLocal.queryForList(queryEntryByNameSql);
 
}catch(Exception e){
 
logger.info("判断数据库中是否存在该词条 sql 出错了"+queryEntryByNameSql);
 
}
 
 
 
if(list.size()==0){
 
Document doc =null;
 
try{
 
// 5000 = 5秒
 
doc =Jsoup.connect(url).timeout(50000).get();
 
 
if(doc.select("sup").size()>0){
 
doc.select("sup").remove();//html页面的标注信息
 
}
 
if(doc.select(".mw-editsection").size()>0){
 
doc.select(".mw-editsection").remove();//删除编辑
 
}
 
 
 
//获取html正文信息
 
Elements bodys = doc.select("#mw-content-text > *");
 
StringBuffer text =newStringBuffer();
 
 
 
//解析 html 获取 概述 和 正文
 
for(Element el : bodys){
 
String elText = el.text().trim();
 
if(!StringUtil.isBlank(elText)){
 
elText = converter.convert(elText);
 
 
if(el.attr("id").equals("toc")){//目录
 
text.append("@@!@@");//定义特殊符号,分割 概述和正文
 
}
 
 
if(el.tagName().equals("h2")){//分类标题
 
text.append("<h2>"+elText+"</h2>");
 
}
 
if(el.tagName().equals("p")){//判断当前文本标签
 
text.append("<p>"+elText+"</p>");
 
}
 
}
 
 
}
 
 
 
String describe ="";//概述
 
String content ="";//正文
 
if(!StringUtil.isBlank(text.toString())){
 
if(text.indexOf("@@!@@")>-1){//判断当前text是否存在 正文和概述的分隔符
 
 
describe = text.substring(0, text.indexOf("@@!@@"));
 
content = text.substring(text.indexOf("@@!@@")+5,text.length());
 
 
logger.info("概述:--------------");
 
logger.info(describe);
 
logger.info("正文:--------------");
 
logger.info(content);
 
 
 
}else{//如果没有 @@!@@ 分隔符的话,默认用第一段作为概述
 
if(text.indexOf("<h2>")>-1){//默认用第一个分类标题 做分割
 
describe = text.substring(0, text.indexOf("<h2>"));
 
content = text.substring(text.indexOf("<h2>")+4,text.length());
 
}else{//用第一个p标签做分割
 
describe = text.substring(0, text.indexOf("</p><p>")+4);
 
content = text.substring(text.indexOf("</p><p>")+7,text.length());
 
}
 
 
 
logger.info("概述:--------------");
 
logger.info(describe);
 
logger.info("正文:--------------");
 
logger.info(content);
 
 
 
}
 
}
 
 
 
//添加词条信息到数据库
 
Entry entry =newEntry();
 
entry.setName(name);
 
entry.setCategoryId(categoryId);
 
entry.setAuthor("admin");
 
entry.setDescribe(describe);
 
entry.setContent(content);
 
entry.setWikiid(entryId);
 
 
try{
 
entryService.insertSelective(entry);
 
logger.info(JSON.toJSONString(entry));
 
}catch(Exception e){
 
logger.info("词条插入出错:-------"+JSON.toJSONString(entry));
 
}
 
 
 
 
logger.info("属性:--------------");
 
//获取页面属性信息 infobox
 
Elements infoboxs = doc.select(".infobox");
 
if(infoboxs.size()>0){//查找属性
 
Element info = infoboxs.get(0);
 
 
Elements trs = info.select("tr");
 
for(Element tr : trs){
 
String key ="";
 
String val ="";
 
if(tr.select("th").size()>0&& tr.select("td").size()>0){// key=th 、val=td
 
key = tr.select("th").text();
 
val = tr.select("td").text();
 
}elseif(tr.select("th").size()==0&& tr.select("td").size()>=2){// key=td 、val=td
 
key = tr.select("td").get(0).text();
 
val = tr.select("td").get(1).text();
 
}
 
 
 
key = converter.convert(key);
 
val = converter.convert(val);
 
if(!StringUtil.isBlank(key)&&!StringUtil.isBlank(val)){
 
logger.info(key+" : "+val );
 
Meta m =newMeta();
 
//判断属性表里是否已存在该属性
 
String metaSql =" select t.id from bk_meta t where t.category_id = '-' and t.name = '"+key+"' ";//is not null
 
// logger.info("判断该 '"+key+"' 属性是否已存在------"+metaSql);
 
List<Map<String,Object>> metaList = jtLocal.queryForList(metaSql);
 
if(metaList.size()==0){
 
m.setCategoryId("-");
 
m.setName(key);
 
try{
 
metaService.insertSelective(m);
 
}catch(Exception e){
 
logger.info("属性插入出错:-------"+JSON.toJSONString(m));
 
}
 
 
}else{
 
m.setId(Long.parseLong(metaList.get(0).get("id").toString()));
 
}
 
 
Metadata metadata =newMetadata();
 
metadata.setEntryId(entry.getId());
 
metadata.setMetaId(m.getId());
 
metadata.setValue(val);
 
metadata.setUpdateTime(date);
 
try{
 
metadataService.insertSelective(metadata);
 
}catch(Exception e){
 
logger.info("属性值 插入出错:-------"+JSON.toJSONString(metadata));
 
e.printStackTrace();
 
}
 
 
}
 
 
}
 
}
 
 
 
}catch(IOException e1){
 
logger.error(url+" 连接超时!!!");
 
}
 
 
}
 
 
Long eTime =System.currentTimeMillis();
 
logger.info(name+" --------------------------------------------解析结束:---------------------------------耗时--"+(eTime-sTime)+"毫秒!");
 
logger.info("");
 
logger.info("");
 
logger.info("");
 
logger.info("");
 
logger.info("");
 
logger.info("");
 
 
}

猜你喜欢

转载自blog.csdn.net/npf_java/article/details/50196131