使用Jsoup实现简单的页面信息爬取
首先,简单说一下个人对爬虫的理解(比较简单,以后再完善):爬虫,简单点就是从网站上来爬取你所需要的信息。从这个功能考虑的话,也就简单的分为了一下几步(本篇主要就此展开讨论):1、你需要的网址;2、你所需要的信息;3、获取信息并存储或进行相关处理。其次,简单说几个工具,最开始了解到一个httpclient的神奇东东可以实现功能强大的爬虫功能(个人理解:用java程序来封装数据包,进行网络访问,然后对访问结果进行判断,正确判断的话,再对获取到的网页信息进行解析,可以利用封装好的方法,也可以自己编写匹配过滤规则,从而获取有用的信息),后来又看到一个Jsoup的网页解析便器(比较方便的解析工具)。接下来,详细看了下 官方文档(http://www.open-open.com/jsoup/)(请认真看),又在论坛里看到了几个实例,感觉确实很方便,接下来便开始了一段Jsoup的实践之旅.第一,Jsoup的相关操作:
1. 链接打开方式
一、 File input = new File("D:/test.html");
Document doc = Jsoup.parse(input,"UTF-8","http://baidu.com/");//第三个参数是b //aseURL,当有相对地址时,有该地址补全
二、Document doc = Jsoup.parse("D:/test.html");//直接加载网页文件
三、Connect conn = Jsoup.connect(url);
Document doc = conn.data("query","Java").//请求参数
userAgent("I'm Jsoup").//设置User-Agent
cookie("auth","token").//设置cookie
timeout(3000).//设置连接超时时间
post();//使用post方法访问URL
实例:
public class First {
//public boolean append;
//网页打开方法
public Document openURL(String url){
Document document = null;
try {
document = Jsoup.connect(url).timeout(40000).get();
System.out.println("网页"+url+"访问成功");
} catch (IOException e) {
System.out.println("网页"+url+"打开失败");
}
}
2. 解析规则
(1)jsoup中主要有三种操作对象:Document、Elements及Element。其中:
- Document继承自Element类,它包含页面中的全部数据,通过Jsoup类的静态方法获得;
- Elements是Element的集合类;
- Element是页面元素的实体类,包含了诸多操作页面元素的方法,其中除了类似于jQuery选择器的select方法外,还有大量类似于JS和jQuery的对DOM元素进行操作的方法,如getElementById,text,addClass,等等。
(2)Select方法将返回一个Elements集合,并提供一组方法来抽取和处理结果。
Selector选择器概述
· tagname:通过标签查找元素,比如:a
· ns|tag:通过标签在命名空间查找元素,比如:可以用 fb|name 语法来查找 <fb:name> 元素
· #id:通过ID查找元素,比如:#logo
· .class:通过class名称查找元素,比如:.masthead
· [attribute]:利用属性查找元素,比如:[href]
· [^attr]:利用属性名前缀来查找元素,比如:可以用[^data-] 来查找带有HTML5 Dataset属性的元素
· [attr=value]:利用属性值来查找元素,比如:[width=500]
· [attr^=value], [attr$=value], [attr*=value]:利用匹配属性值开头、结尾或包含属性值来查找元素,比如:[href*=/path/]
· [attr~=regex]:利用属性值匹配正则表达式来查找元素,比如: img[src~=(?i)\.(png|jpe?g)]
· *:这个符号将匹配所有元素
Selector选择器组合使用
· el#id:元素+ID,比如: div#logo
· el.class:元素+class,比如: div.masthead
· el[attr]:元素+class,比如: a[href]
· 任意组合,比如:a[href].highlight
· ancestorchild:查找某个元素下子元素,比如:可以用.body p 查找在"body"元素下的所有 p元素
· parent> child:查找某个父元素下的直接子元素,比如:可以用div.content > p 查找 p 元素,也可以用body > * 查找body标签下所有直接子元素
· siblingA+ siblingB:查找在A元素之前第一个同级元素B,比如:div.head + div
· siblingA~ siblingX:查找A元素之前的同级X元素,比如:h1 ~ p
· el,el, el:多个选择器组合,查找匹配任一选择器的唯一元素,例如:div.masthead, div.logo
伪选择器selectors
· :lt(n):查找哪些元素的同级索引值(它的位置在DOM树中是相对于它的父节点)小于n,比如:td:lt(3) 表示小于三列的元素
· :gt(n):查找哪些元素的同级索引值大于n,比如: div p:gt(2)表示哪些div中有包含2个以上的p元素
· :eq(n):查找哪些元素的同级索引值与n相等,比如:form input:eq(1)表示包含一个input标签的Form元素
· :has(seletor):查找匹配选择器包含元素的元素,比如:div:has(p)表示哪些div包含了p元素
· :not(selector):查找与选择器不匹配的元素,比如: div:not(.logo) 表示不包含 class=logo 元素的所有 div列表
· :contains(text):查找包含给定文本的元素,搜索不区分大不写,比如: p:contains(jsoup)
· :containsOwn(text):查找直接包含给定文本的元素
· :matches(regex):查找哪些元素的文本匹配指定的正则表达式,比如:div:matches((?i)login)
· :matchesOwn(regex):查找自身包含文本匹配指定正则表达式的元素
· 注意:上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素index为1等
可以查看Selector API参考来了解更详细的内容
第二,Jsoup实例
1. 爬取一个源URL(http://apk.hiapk.com/)下的链接(安卓游戏),并获取新链接(安卓游戏)的内容
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class TestJsoup {
public Document getDocument (String url){
try {
return Jsoup.connect(url).get();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
TestJsoup t = new TestJsoup();
Document doc= t.getDocument("http://apk.hiapk.com/");
//Document doc = t.getDocument("http://www.weather.com.cn/html/weather/101280101.shtml");
//Document doc = t.getDocument("http://www.cnblogs.com/xiaoMzjm/p/3899366.html");//zijichangshi
// 获取目标HTML代码
//找到游戏链接,并跳转到游戏界面
Elements elements1 = doc.select("a[title = 安卓游戏]");
String href = elements1.attr("href");//获得链接
System.out.println(href);//控制台查看
Document docgame = t.getDocument(href);//打开获取的新链接
System.out.println(docgame.select("title").text());
Elements elements2 = docgame.select("a[class = s2]");
String href2 = elements2.attr("href");
String txt = elements2.text();
System.out.println(href2);
Document docgame2 = t.getDocument(href2);
System.out.println(docgame2.select("title").text());
}
}
2 . 获取源URL下所有游戏的链接及其相关游戏详细信息
步骤:
1)源URL |
2)游戏页面 |
3) 游戏分类页面 |
4) 单个游戏的链接 |
5) 单个游戏的详细信息 |
1) 源URL : http://apk.hiapk.com/
2) 游戏页:
//获取 游戏 链接
Elements gameLink = doc.select("a[title = 游戏-安卓市场]");
String url2 = gameLink.attr("abs:href");
Document doc2 = first.openURL(url2);
3) 游戏分类页
//获取 游戏分类 链接
Elements gameLink2 = doc2.select("div.cate_list_box");
Elements gameLinkType = gameLink2.select("a");
int length = gameLinkType.size();
4) 单个游戏的链接:可能遇到多页的情况,这时候要进行分页处理
简单思路:获取所有分页的URL , 求并集便是一类游戏下的所有游戏
//获取游戏分类下的游戏列表
public void GameTypeFetch(String url, String table){
First gtfetch = new First();
Document doc = gtfetch.openURL(url);
Elements gameLink = doc.select("ul#appSoftListBox").select("li");
int length = gameLink.size();
String urlGame[] = new String[length];
String nameGame[] = new String[length];
int temp = 0;
/*for(int i=0; i<length; i++){
urlGame[i] = gameLink.get(2*i+1).attr("abs:href");
nameGame[i] = gameLink.get(2*i+1).text();
System.out.println(i+" : "+urlGame[i]+" : "+nameGame[i]);
}*/
System.out.println(" "+length);
for(Element e : gameLink){//单个游戏的链接
urlGame[temp] = e.select("a").get(1).attr("abs:href");
nameGame[temp] = e.select("a").get(1).text();
System.out.println(" "+temp+" : "+urlGame[temp]+" : "+nameGame[temp]);
gtfetch.gameItems(nameGame[temp],urlGame[temp],false,0,table);
temp++;
}
}
5)单个游戏的详细信息
注意对其它版本的处理
//获取游戏的具体详细信息
public void gameItems(String gameName, String gameLink, boolean otherVersion, int version, String table){
//int tableindex = 0;
//变量声明,存储游戏相关信息
String name = gameName;
String link = gameLink;
//属性1
int starsize = 5;
String star[] =new String[starsize];
String starNUM = null;
int numEVAL = 0;//有多少人评分
//属性2
String des = null;
String updes = null;
//属性3
String author = null;
String down = null;
String size = null;
String type = null;
String language = null;
String time = null;
//String name = null;
//属性4
int VSNUM = 0;
String otherVS[];
//获取当前游戏信息
Elements details;
First gtfetch = new First();
Document doc = gtfetch.openURL(link);
boolean valid = gtfetch.isValid();
if(valid==true){
//System.out.println(eee);
//获取属性3
details = doc.select("div.line_content");
if(!details.isEmpty()){
System.out.println(details.size());
author = details.get(0).select("span").get(1).text();
down = details.get(1).select("span").get(1).text();
size = details.get(2).select("span").get(1).text();
type = details.get(3).select("span").get(1).text();
language = details.get(4).select("span").get(1).text();
time = details.get(7).select("span").get(1).text();
//获取属性2
des = doc.select("pre#softIntroduce").text();
updes = doc.select("pre.soft_imprint_font").text();
//获取属性1
Elements eval = doc.select("div.star_line");
for(Element e : eval){
star[--starsize] = e.text();
}
starNUM = doc.select("div.star_num").text();
numEVAL = Integer.parseInt(doc.select("span#startCount").text());//有多少人评分
if(!otherVersion){
//typelength++;
//tableindex = typelength;
//获取属性4
Elements otherversions = doc.select("div#otherSoftBox");
Elements versions = otherversions.select("dl.soft_item_dl");
int versionlength = versions.size();
VSNUM = versionlength + 1;
//otherVS = new String[otherVSNUM];
//System.out.println(otherVSNUM);
for(int ind=(versions.size()-1);ind>=0;ind--){
String otherurl = versions.get(ind).select("a[href]").first().attr("abs:href");
gameItems(name,otherurl,true,(versions.size()-ind+1),table);
}
}else{
typelength++;
System.out.println(name+" 没有其他版本!");
VSNUM = version;
tableindex = typelength;
}
System.out.println(name+" "+link+" "+author+" "+down+" "+size+" "+type+" "+" "+time+" "+starNUM+" "+numEVAL+" "+VSNUM);
}
}
}
综上,使用Jsoup也可以实现简单的爬虫程序,但更适合于网页的解析,爬虫程序,一般都有一个基本的框架,通过一系列的种子URL,获取所需链接(往往数量较多),这时,便遇到了爬取到的大量链接的访问问题,一般,将链接分为两大部分,以访问的链接和带访问的链接(用队列或者堆栈存储,方便操作),有时,会将采集到的信息用数据库进行存储,以方便对采集的信息进行进一步的处理(实现了一个简单的mysql数据库的实例)。该文主要是以一个简单实例来介绍Jsoup的使用,从而对Jsoup有一个更深刻的认识,同时,对爬虫也有一个初步的了解,针对于爬虫的复杂程度,所采用的爬虫结构也会有所变化!
望对刚刚入门的你,会有所帮助!