爬虫是个非常有意思的东西,它是根据网页上的文件结构来抓取相应内容的技术。由于最近ACM省赛在即,我负责统计做题,所以便用java写了个抓取BestCoder比赛情况的爬虫程序。
先来说说爬虫的几种抓取策略。
抓取策略
在爬虫系统中,待抓取URL队列是很重要的一部分。待抓取URL队列中的URL以什么样的顺序排列也是一个很重要的问题,因为这涉及到先抓取那个页面,后抓取哪个页面。而决定这些URL排列顺序的方法,叫做抓取策略。下面重点介绍几种常见的抓取策略:
1.深度优先遍历策略
深度优先遍历策略是指网络爬虫会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续跟踪链接。我们以下面的图为例:
遍历的路径:A-F-G E-H-I B C D
2.宽度优先遍历策略
宽度优先遍历策略的基本思路是,将新下载网页中发现的链接直接插入待抓取URL队列的末尾。也就是指网络爬虫会先抓取起始网页中链接的所有网页,然后再选择其中的一个链接网页,继续抓取在此网页中链接的所有网页。还是以上面的图为例:
遍历路径:A-B-C-D-E-F G H I
3.反向链接数策略
反向链接数是指一个网页被其他网页链接指向的数量。反向链接数表示的是一个网页的内容受到其他人的推荐的程度。因此,很多时候搜索引擎的抓取系统会使用这个指标来评价网页的重要程度,从而决定不同网页的抓取先后顺序。
在真实的网络环境中,由于广告链接、作弊链接的存在,反向链接数不能完全等他我那个也的重要程度。因此,搜索引擎往往考虑一些可靠的反向链接数。
4.Partial PageRank策略
Partial PageRank算法借鉴了PageRank算法的思想:对于已经下载的网页,连同待抓取URL队列中的URL,形成网页集合,计算每个页面的PageRank值,计算完之后,将待抓取URL队列中的URL按照PageRank值的大小排列,并按照该顺序抓取页面。
如果每次抓取一个页面,就重新计算PageRank值,一种折中方案是:每抓取K个页面后,重新计算一次PageRank值。但是这种情况还会有一个问题:对于已经下载下来的页面中分析出的链接,也就是我们之前提到的未知网页那一部分,暂时是没有PageRank值的。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有入链传递进来的PageRank值进行汇总,这样就形成了该未知页面的PageRank值,从而参与排序。下面举例说明:
5.OPIC策略策略
该算法实际上也是对页面进行一个重要性打分。在算法开始前,给所有页面一个相同的初始现金(cash)。当下载了某个页面P之后,将P的现金分摊给所有从P中分析出的链接,并且将P的现金清空。对于待抓取URL队列中的所有页面按照现金数进行排序。
6.大站优先策略
对于待抓取URL队列中的所有网页,根据所属的网站进行分类。对于待下载页面数多的网站,优先下载。这个策略也因此叫做大站优先策略。
我用的是开源的Jsoup来完成功能的。由于BC每次比赛都会有一个相应的cid,搜索时是以用户名为关键字,以get方式提交的。BC网站会根据学校进行分类,每所学校的用户可以在一个页面下找到。所以我先去那个网站找到所有用户名。再去相应的那场比赛用用户名搜索抓取名次和做题题数。
哈哈原理十分简单。上代码
先用MyEclipse建一个WEB工程,建一个DoBestCoders,java文件
package SpiderMan;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class DoBestCoders {
private String url = null;
private Document doc = null;
private Elements body = null;
private Elements table = null;
private Elements username = null;
public Elements getUsername() throws IOException {
url = "http://bestcoder.hdu.edu.cn/ranklist.php?action=search&type=school&keyword=%D5%E3%BD%AD%BF%C6%BC%BC%D1%A7%D4%BA";
doc = Jsoup.connect(url).get();
//username = doc.getElementsByClass("level5");
username = doc.select("tbody");
//table.select("img[src$=.gif]").attr("src", "http://bestcoder.hdu.edu.cn/images/country/1.gif");
return username.select("a[href]");
}
public boolean isDoProblem(int cid, Element ele) throws IOException { //判断是否做了题目
//boolean flag;
// Elements numOfproblems = null;
String username = ele.text();
url = "http://bestcoder.hdu.edu.cn/contests/contest_ranklist.php?cid=";
url += cid;
url += "&action=search&keywords=";
url += username;
doc = Jsoup.connect(url).get();
if( doc.select("tbody").select("tr").select("td").first() != null ) {
return true;
}
return false;
}
public String getProblemSituation(int cid, Element ele) throws IOException {
String ps = "";
String username = ele.text();
Elements numOfproblems = null;
Element isrank = null;
int size;
String rank = "-1";
url = "http://bestcoder.hdu.edu.cn/contests/contest_ranklist.php?cid=";
url += cid;
url += "&action=search&keywords=";
url += username;
doc = Jsoup.connect(url).get();
if(( numOfproblems=doc.select("tbody").select("div") ) == null) {
size = 0;
// rank = "-1";
}
else {
size = numOfproblems.size();
size /= 2; //时间和是否做出
if( (isrank = doc.select("tbody").select("tr").select("td").first()) != null )
rank =isrank .text();
}
ps += ("<tr><td>" + username + "</td>");
ps += ("<td>" + size + "</td>");
ps += ("<td>" + rank + "</td>");
ps += "</tr>";
return ps;
}
}
<%@page import="org.jsoup.select.Elements"%>
<%@page import="org.jsoup.nodes.Element"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>SpiderMan</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<table><tr><th>用户名</th><th>做题数</th><th>排名</th></tr>
<jsp:useBean id="spiderman" class="SpiderMan.DoBestCoders" scope="page"></jsp:useBean>
<%
Elements elements = spiderman.getUsername();
for(Element e : elements) {
if(spiderman.isDoProblem(688, e) == true)
out.print(spiderman.getProblemSituation(688, e));
}
%>
</table>
</body>
</html>
运行结果: