- 论坛徽章:
- 0
|
首先感谢chinaunix保留我的文章!
我这次要介绍的是如何抽取正文,这部分是最为核心的.因为如果不能很好的提取原有文章的内容和样式,那么搜索出来的东西
就会惨不忍睹.根本就没有使用价值
在做正文抽取模块之前我曾经参考过很多抽取模式,有配置模版的,有搞视觉匹配的.有搞关键字识别的.我挨个做了分析
首先配置摸版是不太现实的,因为我在搜索技术资讯的时候,根本不知道会搜索到哪个网站,也根本没精力去配置摸版.所以这个行不通
基于视觉效果的分析,这个难度比较大,而且只适合于规范的网站,而现在很多网站根本不规范,广告链接漫天飞.人家都把最好的
位置留给广告了.而且我一直怀疑这个模式的可行性,它只是一个善意的推测.所以这方面没做过多尝试
我在想,是否有种简单的方法呢?难道就没有什么共性吗?
我想所有的正文应该有个共同的特点,那就是正文的长度应该超过其他文字组合的长度.很少会有一句话的正文,很少会有长度
短于标题的正文.所以这个应该成为一个突破口.
接下来,有一个很重要的问题,那段最长的正文在哪里呢?
肯定是在一个TABLE,或者DIV,或者ParagraphTag里.那好,那就找到那个包含文字最多的DIV或者TABLE.
不过问题又来了,HTML页面,经常是HTML元素的长度超过了正文的长度,有时候混入了不少的JAVASCRIPT.这些元素
HTMLPARSER经常会误认为是正文加以识别,导致很多正文竟然是一段JAVASCRIPT.
祛除杂质是一个关键,这里面要把那些HTML中常用的标签,以及连接中正文去除掉,否则,你搜索出来的很可能是别的什么,尤其
当正文文字相对较少的时候.我在搜索SOHU页面的时候就经常遇到这个问题,原因是SOHU的页面不是严格按照DIV布局,里面有很多广告
的JAVASCRIPT。新浪的有些页面也有这个现象,反到是一些中小网站的布局很规范,呵呵,真奇怪了。
做完这些工作后,我发现仍然有些网页不能正常抓取,原因是HTMLPARSER对TEXT的认识有问题.例如一段文字在
ParagraphTag中或者span中包含的,就不能很好的识别.所以要单独做个抽取ParagraphTag内容的函数.
做完这些步骤后,有一个问题出来了就是正文中包含的图片,连接,粗体,正常的表格.这些问题一个个的冒出来.既然问题出来了
那就要一个个的解决.解决了这些难题.我的网站抓取文章的质量就大大的提高了85%的准确率,基本达到实用阶段.我网站上的正文快照基本和原文保持一致.
提供几个例子,大家可以看下原文和我抓取的有多少不同
1. http://www.itsubway.com/context/20071218/11762.htm
这个是单纯获取正文的例子,其中有粗体标签和链接
2 http://www.itsubway.com/context/20071218/12041.htm
这个是正文里混有图片和表格.
为了感谢chinaunix保留我的帖子,感谢大家看我的帖子.我把抽取正文的部分代码和大家共享.这些代码基本解决了我在
上面列举出来的问题。包括正文中混有图片,连接,粗体,表格等。大家要是有兴趣可以改造下这些代码,完整的代码在附件中
代码中有全部的抽取算法.你可以新建个项目导入这些类,稍微调整下,就可以运行.其中有个字串替换函数,这个我没有加,诸位可以自己
随便找个这样的函数.你可以用我提供的代码试验下,看看抽取的效果如何.其中ExtractContext是程序执行的入口.context.vm是我定义的生成正文的摸版.你可以自己定义喜欢的格式.
请大家重点看protected List extractHtml(Node nodeP, PageContext context, String siteUrl)
这个函数是正文抽取的入口。我的这些函数写的不是很规范,别笑话!
最后,有几句话想说下,我看到有个评论说我是个AD广告贴,我对这种看法表示理解,从客观的角度说,我写这帖子
既是和大家分享一些思路,同时自然也是在为自己的思路做个宣传。如果双方都有所收益,那也不是什么坏事情。难道你喜欢研究半天
然后默默无闻的藏起来吗?互联网是个开放的平台,应该要能包容一切不同的做法,理念。尤其是我们这些没日没夜辛苦做技术的人。
我办这个网站的初衷一方面是想把自己的那点点技术发挥出作用来,找出一些好的IT网站和大家分享。另一方面也是想能使自己或
者帮助其他的程序员开拓下视野和思路。
我感谢CHINAUNIX的管理员保留我的帖子,我相信有容乃大!
/ /**
* 递归钻取正文信息 --- 详细见附件
* @param nodeP
* @return
*/
protected List extractHtml(Node nodeP, PageContext context, String siteUrl)
throws Exception {
NodeList nodeList = nodeP.getChildren();
boolean bl = false;
if ((nodeList == null) || (nodeList.size() == 0)) {
if (nodeP instanceof ParagraphTag) {
ArrayList tableList = new ArrayList();
StringBuffer temp = new StringBuffer();
temp.append("<p style=\"TEXT-INDENT: 2em\">" ;
tableList.add(temp);
temp = new StringBuffer();
temp.append("</p>" .append(lineSign);
tableList.add(temp);
return tableList;
}
return null;
}
if ((nodeP instanceof TableTag) || (nodeP instanceof Div)) {
bl = true;
}
if (nodeP instanceof ParagraphTag) {
ArrayList tableList = new ArrayList();
StringBuffer temp = new StringBuffer();
temp.append("<p style=\"TEXT-INDENT: 2em\">" ;
tableList.add(temp);
extractParagraph(nodeP, siteUrl, tableList);
temp = new StringBuffer();
temp.append("</p>" .append(lineSign);
tableList.add(temp);
return tableList;
}
ArrayList tableList = new ArrayList();
try {
for (NodeIterator e = nodeList.elements(); e.hasMoreNodes() {
Node node = (Node) e.nextNode();
if (node instanceof LinkTag) {
tableList.add(node);
setLinkImg(node, siteUrl);
} else if (node instanceof ImageTag) {
ImageTag img = (ImageTag) node;
if (img.getImageURL().toLowerCase().indexOf("http://" < 0) {
img.setImageURL(siteUrl + img.getImageURL());
} else {
img.setImageURL(img.getImageURL());
}
tableList.add(node);
} else if (node instanceof ScriptTag ||
node instanceof StyleTag || node instanceof SelectTag) {
} else if (node instanceof TextNode) {
if (node.getText().length() > 0) {
StringBuffer temp = new StringBuffer();
String text = collapse(node.getText()
.replaceAll(" ", ""
.replaceAll(" ", "" );
temp.append(text.trim());
tableList.add(temp);
}
} else {
if (node instanceof TableTag || node instanceof Div) {
TableValid tableValid = new TableValid();
isValidTable(node, tableValid);
if (tableValid.getTrnum() > 2) {
tableList.add(node);
continue;
}
}
List tempList = extractHtml(node, context, siteUrl);
if ((tempList != null) && (tempList.size() > 0)) {
Iterator ti = tempList.iterator();
while (ti.hasNext()) {
tableList.add(ti.next());
}
}
}
}
} catch (Exception e) {
return null;
}
if ((tableList != null) && (tableList.size() > 0)) {
if (bl) {
StringBuffer temp = new StringBuffer();
Iterator ti = tableList.iterator();
int wordSize = 0;
StringBuffer node;
int status = 0;
StringBuffer lineStart = new StringBuffer(
"<p style=\"TEXT-INDENT: 2em\">" ;
StringBuffer lineEnd = new StringBuffer("</p>" + lineSign);
while (ti.hasNext()) {
Object k = ti.next();
if (k instanceof LinkTag) {
if (status == 0) {
temp.append(lineStart);
status = 1;
}
node = new StringBuffer(((LinkTag) k).toHtml());
temp.append(node);
} else if (k instanceof ImageTag) {
if (status == 0) {
temp.append(lineStart);
status = 1;
}
node = new StringBuffer(((ImageTag) k).toHtml());
temp.append(node);
} else if (k instanceof TableTag) {
if (status == 0) {
temp.append(lineStart);
status = 1;
}
node = new StringBuffer(((TableTag) k).toHtml());
temp.append(node);
} else if (k instanceof Div) {
if (status == 0) {
temp.append(lineStart);
status = 1;
}
node = new StringBuffer(((Div) k).toHtml());
temp.append(node);
} else {
node = (StringBuffer) k;
if (status == 0) {
if (node.indexOf("<p" < 0) {
temp.append(lineStart);
temp.append(node);
wordSize = wordSize + node.length();
status = 1;
} else {
temp.append(node);
status = 1;
}
} else if (status == 1) {
if (node.indexOf("</p") < 0) {
if (node.indexOf("<p") < 0) {
temp.append(node);
wordSize = wordSize + node.length();
} else {
temp.append(lineEnd);
temp.append(node);
status = 1;
}
} else {
temp.append(node);
status = 0;
}
}
}
}
if (status == 1) {
temp.append(lineEnd);
}
if (wordSize > context.getNumber()) {
context.setNumber(wordSize);
context.setTextBuffer(temp);
}
return null;
} else {
return tableList;
}
}
return null;
}
|
|