git地址:https://github.com/CrawlScript/WebCollector
业务需要爬取一个网站所有手机信息 ,最开始用了crawler4j这个框架,挺简单的,但是发现不能满足我的需求;只支持单页面信息抓取,但是我是要多页面抓取;需要在一级页面抓取到所有的二级页面的链接,再加入所有二级页面的链接,进行抓取所有三级页面的信息;后来改成了webcontroller,发现可以实现我的需求:
爬虫原理就是抓取到页面(page)的所有信息,输出为一个html,然后用jsoup去解析这个html,根据id、class等定位到对应的页面元素,然后进行取值。
注意事项:这个框架有个回滚机制,如果在添加一条数据的时候,里面有一个地方报异常的,这一整条数据都不会添加,所以为了数据全量,一定要先把控制台输出的代码异常全部解决!
一般情况是 Elements 为空缺去取数据导致报异常,一般是判断 elements != null && elements .size()>0
上代码:(www.***.cn改成自己要抓取的网址
)
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.berkeley.BreadthCrawler;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/**
* Crawling news from github news
*
* @author hu
*/
public class DemoAutoNewsCrawler extends BreadthCrawler {
static int grade = 1;//爬虫的深度,第一次为1
static List<String> list = new ArrayList<String>();//url种子
/**
* @param crawlPath crawlPath is the path of the directory which maintains
* information of this crawler
* @param autoParse if autoParse is true,BreadthCrawler will auto extract
* links which match regex rules from pag
*/
public DemoAutoNewsCrawler(String crawlPath, boolean autoParse) {
super(crawlPath, autoParse);
/*start pages*/
this.addSeed("http://www.***.cn/cell_phone_index/subcate57_list_1.html");
//循环添加所有链接
// for(int pageIndex = 1; pageIndex <= 1; pageIndex++) {
// String seedUrl = String.format("https://list.jd.com/list.html?cat=9987,653,655&page=1&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main", pageIndex);
// this.addSeed(seedUrl);
// }
setThreads(1);
getConf().setTopN(100);
}
public void visit(Page page, CrawlDatums next) {
String url = page.url();
/*if page is news page*/
if (page.matchUrl("http://www.***.cn/.*")) { // .*代表后面匹配所有
Document doc = page.doc();
//爬虫的深度为1
if(grade == 1){
Element element = doc.getElementById("J_PicMode");
Elements elements = element.getAllElements();
for (Element el: elements) {
Elements e = el.getElementsByClass("pic");
for (Element e1: e) {
String s = el.children().attr("href");
if(s != null && !"".equals(s)){
list.add(el.children().attr("href"));//加入第二级链接
}
System.out.println(el.children().attr("href"));
}
}
}
//爬虫的深度为2
else if(grade == 2){
Elements e = doc.getElementsByClass("_j_MP_more section-more");
for (Element e1: e) {
String s = e.attr("href");
if(s != null && !"".equals(s)){
list.add(e.attr("href"));//加入第三级链接
}
}
}else if(grade == 3){
Elements e1 = doc.getElementsByClass("product-model__name");
for (Element e: e1) {
System.out.println("手机型号:" + e1.text());
}
if (doc.select("#newPmVal_0") != null) {
System.out.println("上市日期:" + doc.select("#newPmVal_0").get(0).text());
}
}
}
}
public static void main(String[] args) throws Exception {
DemoAutoNewsCrawler crawler = new DemoAutoNewsCrawler("crawl", true);
/*start crawl with depth of 4*/
crawler.start(4);
System.out.println("爬虫深度:" + grade);
System.out.println("种子大小:"+list.size());
System.out.println("第一次执行完毕===============================");
//提升深度
grade++;
for(int pageIndex = 1; pageIndex <= 2; pageIndex++) {
System.out.println("加入的子链接:" + list.get(pageIndex-1));
String seedUrl = String.format("http://www.***.cn"+list.get(pageIndex-1), pageIndex);
crawler.addSeed(seedUrl);
}
//子链接加入完毕之后清空list
list.clear();
//第二次执行
crawler.start(4);
System.out.println("爬虫深度:" + grade);
System.out.println("种子大小:"+list.size());
System.out.println("第二次执行完毕===============================");
//提升深度
grade++;
for(int pageIndex = 1; pageIndex <= 2; pageIndex++) {
System.out.println("加入的子链接:" + list.get(pageIndex-1));
String seedUrl = String.format("http://www.***.cn"+list.get(pageIndex-1), pageIndex);
crawler.addSeed(seedUrl);
}
//第三次执行
crawler.start(4);
System.out.println("爬虫深度:" + grade);
System.out.println("种子大小:"+list.size());
System.out.println("第三次执行完毕===============================");
}
}
使用的maven,pom.xml依赖:
<dependencies>
<dependency>
<groupId>cn.edu.hfut.dmic.webcollector</groupId>
<artifactId>WebCollector</artifactId>
<version>2.73-alpha</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId> <!-- jsoup用于解析html用的 -->
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
</dependencies>
注意事项:
页面上有些元素是 <a class="a b"> class中间是用空格隔开的,如果我们要取它们,则需要:
doc.select(".a.b") 或者doc.select(".a .b")中间也用空格,才能取到!