使用JRegex抽取网页信息
当网络爬虫将网页下载到磁盘上以后,需要对这些网页中的内容进行抽取,为索引做准备。一个网页中的数据大部分是HTML标签,索引肯定不会去索引这些标签。也就是说,这种信息是没有用处的信息,需要在抽取过程中过滤掉。另外,一个网页中一般会存在广告信息、锚文本信息,还有一些我们不感兴趣的信息,都被视为垃圾信息,如果不加考虑这些内容,抽取出来的信息不仅占用存储空间,而且在索引以后,为终端用户提供检索服务,用户检会索到很多无用的垃圾信息,势必影响用户的体验。
这里,针对论坛,采用配置模板的方式来实现信息的抽取。使用的工具可以到http://jregex.sourceforge.net上下载,JRegex是一个基于Java的正则库,可以通过在正则模板中指定待抽取信息的变量,在抽取过程中会将抽取到的信息赋给该变量,从而得到感兴趣的信息。而且,JRegex库支持多级分组匹配。
为了直观,假设,有一个论坛的一个网页的源代码形如:
<a id="anchor">标题</a>
<cont>
<author>a1</author>
<time>2009</time>
<post>p1</post>
<author>a2</author>
<time>2008</time>
<post>p2</post>
<author>a3</author>
<time>2007</time>
<post>p3</post>
<author>a4</author>
<time>2006</time>
<post>p4</post>
<author>2005</author>
<time>t5</time>
<post>p5</post>
</cont>
将该网页代码文件保存为bbsPage.txt文件,准备进行处理。
现在,我们的目标是抽取标题、作者、时间、内容这些内容,当然,标题完全可以从TITLE标签中获得,但是一般网站的一个网页,会在标题文本的后面加上一些目录或者网站名称的信息,例如一个标题为“品味北京奥运中心_奥运加油站_我行我摄_XXX社区_XXX社区是最活跃的社区之一”,一些垃圾信息占了标题的大部分,所以我们不从TITLE标签中抽取标题。
接着,针对上面的网页文件创建信息抽取的正则模板,如下所示:
(?s)<a\sid="anchor">({title}.{1,100}?)\s*(.{1,10240}?)({name}.{1,100}?)\s*<time>({when}.{1,100}?)</time>\s*({content}.{1,100}?)
第一部分为(?s)<a\sid=”anchor”>({title}.{1,100}?)\s*(.{1,10240}?),包含两个组,第一个组名称为title,直接能够抽取到网页的标题文本,并存储到变量title中;而第二个组没有指定组的名称,表示在后面还存在子组,在子组中继续进行抽取。
第二部分为({name}.{1,100}?)\s*({when}.{1,100}?)\s* ({content}.{1,100}?),恰好是父组中未指定组名称的第二个组内中的一个循环。
上面两个模板之间使用一个空格字符隔开,保存到pattern.txt文件中。
可能,你已经观察到了,网页的标题只有一个,而对其他的信息正好能够构成一个循环组,单独从父组中分离出来继续进行抽取,结构很整齐。所以,在使用JRegex库进行编码抽取的时候,主要就是针对两个组进行的。
我基于上面思想和数据,实现了信息的抽取。
首先定义了一个键值对实体类,使用泛型,如下所示:
package org.shirdrn.test; public class Pair<K, V> { private K key;
private V value; public Pair(K key, V value) {
this.key = key;
this.value = value;
} public K getKey() {
return key;
} public void setKey(K key) {
this.key = key;
} public V getValue() {
return value;
} public void setValue(V value) {
this.value = value;
} }
进行信息抽取的核心类为InfomationExtraction,如下所示:
package org.shirdrn.test; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import jregex.Matcher;
import jregex.Pattern; public class InfomationExtraction { private String htmlString;
private String patternString;
private List<Pair<String, String>> dataList = new ArrayList<Pair<String, String>>(); public InfomationExtraction() { } public InfomationExtraction(String htmlFileName, String patternFileName) {
this.htmlString = this.readString(htmlFileName);
this.patternString = this.readString(patternFileName);
} public Pattern[] getPatternArray() {
Pattern[] pa = new Pattern[2];
String[] psa = this.patternString.split(" ");
for (int i = 0; i < psa.length; i++) {
Pattern p = new Pattern(psa[i]);
pa[i] = p;
}
return pa;
} public void extract(Integer sgIndex) { // 指定父组中第sgIndex个组需要在子组中继续进行抽取
Pattern[] pa = this.getPatternArray();
Pattern pBase = pa[0];
Matcher mBase = pBase.matcher(this.htmlString);
if (mBase.find()) {
for (int i = 0; i < mBase.groupCount(); i++) {
String gn = pBase.groupName(i);
if (gn != null) {
String gv = mBase.group(i);
this.dataList.add(new Pair<String, String>(gn, gv));
}
}
String subText = mBase.group(sgIndex);
if (subText != null) {
this.dataList.addAll(this.getSubGroupDataList(pa, subText)); // 调用使用子组正则模板进行抽取的方法
}
}
} public List<Pair<String, String>> getSubGroupDataList(Pattern[] pa, String subText) { // 使用子组正则模板进行抽取
List<Pair<String, String>> list = new ArrayList<Pair<String, String>>();
for (int i = 1; i < pa.length; i++) {
Pattern subp = pa[i];
Matcher subm = subp.matcher(subText);
while (subm.find()) {
for (int k = 0; k < subm.groupCount(); k++) {
String gn = subp.groupName(k);
if (gn != null) {
String gv = subm.group(k);
list.add(new Pair<String, String>(gn, gv));
}
}
}
}
return list;
} public String readString(String fileName) {
InputStream in = this.getClass().getResourceAsStream("/" + fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
} public List<Pair<String, String>> getDataList() {
return this.dataList;
} public static void main(String[] args) {
InfomationExtraction ie = new InfomationExtraction("bbsPage.txt", "pattern.txt");
ie.extract(2);
for (Pair<String, String> p : ie.getDataList()) {
System.out.println("[" + p.getKey() + " " + p.getValue() + "]");
}
}
}
测试一下,如下所示:
[title 标题]
[name a1]
[when 2009]
[content p1]
[name a2]
[when 2008]
[content p2]
[name a3]
[when 2007]
[content p3]
[name a4]
[when 2006]
[content p4]
[name 2005]
[when t5]
[content p5]
至于如何组织抽取到的信息,比如你可能使用Lucene的索引,需要构造Field和Document,那么你就要设计一个实体能够包含一个Document的所有的Field,比如一个Document包括:URL、标题、作者、发表时间、发表内容这五个项,非常容易就能做到。
使用JRegex库,可以非常灵活地配置模板,尤其是对多个组的设计,这要根据你的需要来考虑。
原文声明如下:本文基于署名-非商业性使用-相同方式共享 4.0许可协议发布,欢迎转载、使用、重新发布,但务必保留文章署名时延军(包含链接:http://shiyanjun.cn),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
使用JRegex抽取网页信息的更多相关文章
- [python] 常用正则表达式爬取网页信息及分析HTML标签总结【转】
[python] 常用正则表达式爬取网页信息及分析HTML标签总结 转http://blog.csdn.net/Eastmount/article/details/51082253 标签: pytho ...
- python学习之——爬取网页信息
爬取网页信息 说明:正则表达式有待学习,之后完善此功能 #encoding=utf-8 import urllib import re import os #获取网络数据到指定文件 def getHt ...
- C# HttpWebRequest 绝技 根据URL地址获取网页信息
如果要使用中间的方法的话,可以访问我的帮助类完全免费开源:C# HttpHelper,帮助类,真正的Httprequest请求时无视编码,无视证书,无视Cookie,网页抓取 1.第一招,根据URL地 ...
- 使用htmlunit在线解析网页信息
前言 最近工作上遇到一个问题,后端有一个定时任务,需要用JAVA每天判断法定节假日.周末放假,上班等情况, 其实想单独通过逻辑什么的去判断中国法定节假日的放假情况,基本不可能,因为国家每一年的假期可能 ...
- 使用URLConnection获取网页信息的基本流程
参考自core java v2, chapter3 Networking. 注:URLConnection的子类HttpURLConnection被广泛用于Android网络客户端编程,它与apach ...
- 网页信息抓取进阶 支持Js生成数据 Jsoup的不足之处
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23866427 今天又遇到一个网页数据抓取的任务,给大家分享下. 说道网页信息抓取 ...
- HttpClient+Jsoup 抓取网页信息(网易贵金属为例)
废话不多说直接讲讲今天要做的事. 利用HttpClient和Jsoup技术抓取网页信息.HttpClient是支持HTTP协议的客户端编程工具包,并且它支持HTTP协议. jsoup 是一款基于 Ja ...
- Chrome浏览器如何调试移动端网页信息
Chrome浏览器如何调试移动端网页信息 2017年08月12日 12:42:20 阅读数:835 最近在弄项目,用WebView加载一个页面,想追踪页面中一个按钮的点击事件.这个可能就需要调试这个页 ...
- 常用正则表达式爬取网页信息及HTML分析总结
Python爬取网页信息时,经常使用的正则表达式及方法. 1.获取<tr></tr>标签之间内容 2.获取<a href..></a>超链接之间内容 3 ...
随机推荐
- js 中常用的正则表达式
主要有以下几种: 匹配中文字符的正则表达式: [\u4e00-\u9fa5] 评注:匹配中文还真是个头疼的事,有了这个表达式就好办了哦 获取日期正则表达式:\d{4}[年|\-|\.]\d{1,2}[ ...
- java多线程-多线程常识
线程和进程的区别是什么?进程是一个正在运行的软件程序,打开资源管理器可以看到好多正在运行的进程,而线程则是程序中的顺序控制流,只能使用分配给程序的资源和环境.一个进程至少存在一个线程(主线程). 在j ...
- html5--3.7 input元素(6)
html5--3.7 input元素(6) 学习要点 input元素及其属性 input元素 用来设置表单中的内容项,比如输入内容的文本框,按钮等 不仅可以布置在表单中,也可以在表单之外的元素使用 i ...
- 【Selenium】IE浏览器启动问题
DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();ieCapabilities.setCapabi ...
- 自然语言处理:问答 + CNN 笔记
参考 Applying Deep Learning To Answer Selection: A Study And An Open Task follow: http://www.52nlp.cn/ ...
- Python: PS滤镜--径向模糊
本文用 Python 实现 PS 滤镜中的径向模糊特效,具体的算法原理和效果可以参考之前的博客: http://blog.csdn.net/matrix_space/article/details/3 ...
- 4.13 BJ集训
T1 Mobitel 题目大意: 一个全是正整数的矩阵,求从左上角到右下角的简单路径有多少条路径上数的乘积$>=K$ 思路: 由于整数分块,我们设$f(i,j,k)$表示走到$(i,j)$,$k ...
- [ZJOI 2012] 网络
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2816 [算法] 对每种颜色的边建一棵LCT , 维护联通性即可 时间复杂度 : O( ...
- QQ登陆功能的实现2
QQ登陆功能的实现2 由于看到园子里有朋友说需要讲解和剖析实现的步骤,前面的QQ登陆实现只有代码,所以这篇补上 1. 分析 1). 当运行QQ.exe后会出现qq登陆界面的窗体 2). 我们用spy ...
- bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用splay维护字符串,每个点记录子树的哈希值,然后二分查询. 二分不是把两个点的哈希 ...