抓取维基百科数据。
根据网上调查,现有三种解决方案:
² 使用Apache Nutch爬虫技术,深度抓取页面数据。
² 使用JWPL技术,解析Wikipaia离线数据。
² 使用Jsoup工具类,解析Wikipaia在线html dom元素。
Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。
1. 创建一个新的WebDb (admin db -create).
2. 将抓取起始URLs写入WebDB中 (inject).
3. 根据WebDB生成fetchlist并写入相应的segment(generate).
4. 根据fetchlist中的URL抓取网页 (fetch).
5. 根据抓取网页更新WebDb (updatedb).
6. 循环进行3-5步直至预先设定的抓取深度。
7. 根据WebDB得到的网页评分和links更新segments (updatesegs).
8. 对所抓取的网页进行索引(index).
9. 在索引中丢弃有重复内容的网页和重复的URLs (dedup).
10. 将segments中的索引进行合并生成用于检索的最终index(merge).
Nutch可以广度的抓取html页面,但是不能精确的分析html页面元素,进行数据分析。
JWPL(Java Wikipedia Library)是一个开源的访问wikipeida数据的java api包。它提供的DataMachine 工具类可快速解析wiki格式文件,生成mysql的数据txt文件,可通过mysqlimport 导入到本地数据库中
无法快速有效的从词条正文(wiki格式的数据)中提取有用的信息,需要解析比对wiki中的数据模板,来查找对应的属性
Jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
只能解析制定url的html页面信息,无法像Nutch 一样自动的进行页面抓取。
通过以上的方案分析,任何单独的一种技术都无法实现 精确抓取维基百科数据的功能。但是可以利用这些技术的优点,进行组合查询。
l 利用JWPL技术将下载的wikipedia数据进行解析,存入本地的mysql数据库中。然后根据表之间的关系,遍历分类信息,最后根据分类信息查询对应的词条。
² Category 分类信息表
² Category_outlinks 分类信息和父节点关系表
² Category_pages 分类信息对应词条表
² Page 词条信息表
l 词条信息 = https://zh.wikipedia.org/wiki/ + 词条名称
l 根据Jsoup技术解析 url 获取html信息,找出对应的属性、概述、文本
l 指导性的文章
http://www.cs.bgu.ac.il/~elhadad/nlp12/jwpl/wikification.html
http://www.cnblogs.com/heshizhu/archive/2012/06/26/2564267.html
中文维基 历史下载地址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
http://jingyan.baidu.com/article/90895e0fb9fb5164ec6b0b1e.html
下载 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
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
CREATE DATABASE zhwiki DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
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
在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
/**
* 利用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("
"
+elText+"");
}
if(el.tagName().equals("p")){//判断当前文本标签
text.append("
"
+elText+"");
}
}
}
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("
"
)>-1){//默认用第一个分类标题 做分割
describe = text.substring(0, text.indexOf("
"
));
content = text.substring(text.indexOf("
"
)+4,text.length());
}else{//用第一个p标签做分割
describe = text.substring(0, text.indexOf("
"
)+4);
content = text.substring(text.indexOf("
"
)+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("");
}