抓取维基百科数据

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).

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("

"+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("");
 
 
}

你可能感兴趣的:(Jsoup,数据抓取)