java爬虫抓取动态网页(网页爬虫如何写一个网页程序?(组图) )
优采云 发布时间: 2022-01-04 06:09java爬虫抓取动态网页(网页爬虫如何写一个网页程序?(组图)
)
最近为了练手,对网络爬虫感兴趣,决定自己写一个网络爬虫程序。
先看爬虫应该具备哪些功能。
内容来自()
网页采集的过程类似于图的遍历,网页作为图中的节点,网页中的超链接作为图中的边。通过一个网页的超链接,可以获得其他网页的地址,可以进一步进行网页采集;图的遍历分为广度优先和深度优先两种方法,网页采集过程也是如此。综上所述,Spider采集网页的过程如下:从初始URL采集中获取目标网页地址,通过网络连接接收网页数据,将获取到的网页数据添加到网页库中,分析网页中的其他URL链接,并将它们放在 unvisited 的 URL 集合中,用于网页集合。下图展示了这个过程:
网络采集器聚会
网页采集器通过网址获取该网址对应的网页数据。其实现主要是利用Java中的URLConnection类打开URL对应页面的网络连接,然后通过I/O流读取数据,BufferedReader提供读取数据的缓冲区,提高数据读取效率以及在其下定义的 readLine() 行读取函数。代码如下(异常处理部分省略):
URL url = new URL(“http://www.xxx.com”);
<br />
URLConnection conn = url.openConnection();
<br />
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); <br />
String line = null;
while((line = reader.readLine()) != null)
<br />
document.append(line + "\n");<br />
<br />
网页处理
采集到的单个网页需要进行两种不同的处理,一种是将其作为原创数据放入网页库中进行后续处理;另一种是解析后从中提取出URL连接放入URL池中等待对应网页的集合。
网页的保存需要一定的格式,方便以后批量处理数据。下面是一种存储数据格式,它是从北大天网的存储格式简化而来的:
需要说明的是,添加数据采集日期的原因是网站的很多内容都是动态变化的,比如一些大型门户网站网站的首页内容,也就是说如果不是当天抓取的网页数据很可能有数据过期,所以需要添加日期信息来识别。
URL 提取分为两步。第一步是识别网址,第二步是整理网址。主要原因是网站的部分链接使用了相对路径。如果不组织它们会产生错误。 URL识别主要是通过正则表达式匹配。该过程首先设置一个字符串作为匹配的字符串模式,然后在Pattern中编译后,可以使用Matcher类来匹配相应的字符串。实现代码如下:
public ArrayList urlDetector(String htmlDoc)<br />
{
<br />
final String patternString = "]*\\s*>)";
<br />
Pattern pattern = Pattern.compile(patternString,Pattern.CASE_INSENSITIVE);
<br />
ArrayList allURLs = new ArrayList();
<br />
Matcher matcher = pattern.matcher(htmlDoc);
<br />
String tempURL;
//初次匹配到的url是形如:<a href="http://bbs.life.xxx.com.cn/" target="_blank">
<br />
//为此,需要进行下一步的处理,把真正的url抽取出来,
<br />
//可以对于前两个"之间的部分进行记录得到url
<br />
while(matcher.find()){
<br />
try {
<br />
tempURL = matcher.group(); <br />
tempURL = tempURL.substring(tempURL.indexOf("\"")+1);
<br />
if(!tempURL.contains("\""))
continue;
<br />
tempURL = tempURL.substring(0, tempURL.indexOf("\""));
<br />
} <br />
catch (MalformedURLException e) <br />
{
e.printStackTrace();
}
<br />
}
<br />
return allURLs;
}<br />
根据正则表达式"]*\\s*>)",可以匹配到URL所在的整个标签,形如"",所以循环获取整个标签后,我们需要为了进一步提取真实的URL,我们可以通过截取标签中前两个引号之间的内容来获取这段内容。之后,我们就可以初步得到属于该网页的一组 URL。
接下来,我们将进行第二步,网址排序,即对之前获取的整个页面中的网址集合进行过滤和整合。集成主要针对网页地址为相对链接的部分。由于我们可以很容易的获取到当前网页的网址,因此相对链接只需要在当前网页的网址上加上相对链接字段就可以形成一个完整的网址。一体化。另一方面,在页面收录的综合URL中,有一些页面,例如广告页面,我们不想抓取,或者不重要。这里我们主要针对页面中的广告进行简单的处理。一般网站的广告链接都有对应的展示表达。例如,当链接中收录“ad”等表述时,可以降低该链接的优先级,从而在一定程度上避免对广告链接的抓取。
经过这两个步骤,就可以将采集到的网页网址放入网址池中,然后我们来处理爬虫网址的分配。
调度员
分发者管理URL,负责保存URL池并在Gather获取某个网页后分配新的URL,同时避免重复采集网页。分配器采用设计模式中的单例模式编码,负责提供新的 URL 给 Gather。单例模式尤其重要,因为它涉及到多个线程的后续重写。
重复采集是指物理网页被Gather反复访问而不更新,造成资源浪费。主要原因是没有明确记录访问过的URL,无法区分。因此,Dispatcher 维护着两个列表,“已访问表”和“未访问表”。每个URL对应的页面被爬取后,将该URL放入访问列表,从页面中提取的URL放入未访问列表; Gather向Dispatcher请求一个URL时,首先验证该URL是否在visited表中,然后交给Gather作业。
Spider 启动多个 Gather 线程
目前互联网上有数以亿计的网页,单一的Gather来采集网页显然是低效的,所以我们需要使用多线程的方式来提高效率。 Gather 的功能是采集网页。我们可以通过Spider类开启多个Gather线程来达到多线程的目的。代码如下:
public void start() <br />
{
<br />
Dispatcher disp = Dispatcher.getInstance(); <br />
for(int i = 0; i < gatherNum; i++)<br />
{
<br />
Thread gather = new Thread(new Gather(disp)); <br />
gather.start(); <br />
}<br />
}<br />
在开启线程之后,网页收集器开始作业的运作,并在一个作业完成之后,向 Dispatcher 申请下一个作业,因为有了多线程的
Gather,为了避免线程不安全,需要对 Dispatcher 进行互斥访问,在其函数之中添加 synchronized
关键词,从而达到线程的安全访问。<br />
<br />
<br />