webcollector是一个开源的Java网络爬虫框架。最近的爬虫改用java写了,对这一周的工作进行简要总结。对于内部机制了解不深入,主要侧重在应用。
一、环境搭建
需要安装一个webcollector的jar包,从官网上下载bin文件,解压,根据不同IDE的安装方式进行安装即可。
https://github.com/CrawlScript/WebCollector
关于使用,官网上提供了很多的例子,从GitHub上将整个Webcollector的工程下载下来,参照进行编码。
我直接在官方提供的工程上面建了个文件夹,进行编码。
二、基本使用
两个class,一个Model,一个抓取
1、Model类——封装了要抓取的那些字段
1 package cn.edu.hfut.dmic.webcollector.example.myCrawler.test; 2 3 public class TongModel { 4 String fullName; 5 String shortName; 6 String time; 7 public String getFullName() { 8 return fullName; 9 } 10 11 public void setFullName(String fullName) { 12 this.fullName = fullName; 13 } 14 15 public String getShortName() { 16 return shortName; 17 } 18 19 public void setShortName(String shortName) { 20 this.shortName = shortName; 21 } 22 23 public String getTime() { 24 return time; 25 } 26 27 public void setTime(String time) { 28 this.time = time; 29 } 30 }
2、Crawl类——定义了抓取规则
1 package cn.edu.hfut.dmic.webcollector.example.myCrawler.test; 2 import cn.edu.hfut.dmic.webcollector.crawler.DeepCrawler; 3 //import cn.edu.hfut.dmic.webcollector.example.util.ProxyCollector; 4 import cn.edu.hfut.dmic.webcollector.example.util.JDBCBase; 5 import cn.edu.hfut.dmic.webcollector.model.Links; 6 import cn.edu.hfut.dmic.webcollector.model.Page; 7 import cn.edu.hfut.dmic.webcollector.net.HttpRequesterImpl; 8 import cn.edu.hfut.dmic.webcollector.net.RandomProxyGenerator; 9 import org.jsoup.nodes.Document; 10 import org.jsoup.nodes.Element; 11 import org.jsoup.select.Elements; 12 import org.springframework.jdbc.core.JdbcTemplate; 13 14 import java.util.List; 15 public class CrawlTong extends DeepCrawler{ 16 JdbcTemplate jdbcTemplate = JDBCBase.getInstance().getTemplete2(); 17 public CrawlTong(String crawlPath){ 18 super(crawlPath); 19 } 20 21 @Override 22 public Links visitAndGetNextLinks(Page page) { 23 Document doc = page.getDoc(); 24 boolean iRedirect = page.getResponse().getRedirect(); 25 if(iRedirect) 26 return null; 27 TongModel tongModel = new TongModel(); 28 Elements elementsAll = doc.getAllElements(); 29 tongModel.setFullName(elementsAll.select("a.v3-branding_logo").text()); 30 tongModel.setShortName(elementsAll.select("a.v3-branding_logo").attr("href")); 31 tongModel.setTime("2010-01-21"); 32 saveToDB(tongModel); 33 return null; 34 } 35 public int saveToDB(TongModel m) 36 { 37 System.out.println(m.getFullName()); 38 System.out.println(m.getShortName()); 39 System.out.println(m.getTime()); 40 String sql = "insert into tong(fullName,shortName,timer) values(?,?,?)"; 41 int updates=jdbcTemplate.update(sql,m.getFullName(),m.getShortName(),m.getTime()); 42 return 0; 43 } 44 public static void main(String[] args) throws Exception{ 45 CrawlTong crawler = new CrawlTong("/tong"); 46 crawler.addSeed("https://www.tzg.cn/"); 47 crawler.start(1); 48 } 49 50 }
继承自抓取父类,我采用的是继承DeepCrawler,相应的也可以继承自BreathCrawler。
主要是三个方法,当写完extends DeepCrawler,一般编译器会提示你实现构造方法和重写visitAndGetNextLinks方法,然后需要创建一个main函数
(1)main函数,相当于爬虫的入口
① 新建一个爬虫
② 设定种子,即要爬取的URL
③ 可以设定爬取的线程数,crawler.setThreads(1); 可以并行爬行
④ 设定爬取的深度,crawler.start(10);
关于深度,我的理解是,初始种子是第一层;如果在爬取的过程中不断的加入新的URL,通过第一层新加入的就算第二层;以此类推
通常爬取的时候深度不好确认,最简单的办法就是设定个特别大的值
(2)visitAndGetNextLinks方法,页面解析
采用Jsoup的方法,对页面进行解析 http://www.open-open.com/jsoup/selector-syntax.htm
定义一个Model的对象,通过set的方式把数据存入model
再将Model存放到数据库中
(3)构造方法
关于构造方法,我目前的应用中基本没有修改,后续遇到再补充
(4)JdbcTemplate jdbcTemplate = JDBCBase.getInstance().getTemplete2();
这行代码,是数据库相关的配置
JDNCBase文件中的getTemplete2(),定义了连接哪个数据库
补充1:DAO
WebCollector本身融合了Spring框架(不知道这样说合不合理,本身对Java的框架理解不深),可以通过DAO的形式对数据进行存储。
1 package cn.edu.hfut.dmic.webcollector.example.myCrawler.test; 2 3 import cn.edu.hfut.dmic.webcollector.example.util.GenericDaoImpl; 4 5 import java.util.List; 6 7 public class DataVaryDao extends GenericDaoImpl<DataVaryModel,Long> { 8 9 public DataVaryDao(){super(DataVaryModel.class);} 10 11 public Long add(DataVaryModel model) 12 { 13 return insert(model); 14 } 15 16 public int updata(DataVaryModel model) 17 { 18 return this.update(model); 19 } 20 21 public List<DataVaryModel> getDataBySql(String sql, List<Object> values) 22 { 23 return this.selectBySqlList(sql, values); 24 25 } 26 27 @Override 28 public long getCountBySqlList(String sql, List<Object> values) { 29 return 0; 30 } 31 }
1 dataList = dataDao.getDataBySql("select * from table where xmbm = ? and platform_id = ?", valueList); 2 dataModelDB = dataList.get(0); 3 4 dataVaryModel=new DataVaryModel(); 5 dataVaryModel.setData_id(dataModelDB.getId()); 6 dataVaryModel.setKtje(ktje); 7 dataVaryModel.setXmzt(xmzt); 8 dataVaryModel.setTzrc(tzrc); 9 dataVaryModel.setCreate_date(new Timestamp(new Date().getTime())); 10 dataVaryDao.add(dataVaryModel);
上面就是定义了一个简单的DAO类,这个类也继承自一个基类;然后通过调用DAO中的方法进行数据存储
当然DAO对数据的增删改查等需要自己后台实现
补充2:动态增加种子
爬取的一个常见情况,一边爬网页,一边将网页中的URL加入到爬取队列中。
1 Links links=new Links(); 2 for(int i=0;i<length;i++){ 3 String temp=pre+elements1.get(i).attr("href"); 4 System.out.println(temp); 5 System.out.println(elements1.get(i).text().trim()); 6 links.add(temp); 7 } 8 9 return links;
在visitAndGetNextLinks方法中,定义一个Links类型的变量,将URL加入变量中,返回即可
如上述提及的爬取深度,爬出初始URL页面获取的links就是第二层,一颗树形的结构,随着抓取的增加,深度不断加深
补充3:不动态增加种子,但是爬取新页面
还有一种情况,在爬取的过程中得到了新的URL,但是不想放入对爬取队列,想当下就拿到上面的数据。
1 String newUrl="http://www.xueshandai.com/invest/invest-record/"+xmbm; 2 try { 3 System.out.println(newUrl); 4 String html = requester.getResponse(newUrl).getHtml("UTF-8"); 5 Pattern p = Pattern.compile("<div class=\"jtit3\">(.*?)</div>"); 6 Matcher m = p.matcher(html); 7 System.out.println(m); 8 if(m.find()){ 9 System.out.println("------find---------"); 10 String s=m.group().split(":")[3].split("<")[0]; 11 System.out.println(s.substring(0,s.length()-1)); 12 tzrc = Integer.parseInt(s.substring(0,s.length()-1)); 13 } 14 } catch (Exception e) { 15 e.printStackTrace(); 16 }
requester.getResponse(newUrl).getHtml("UTF-8");
通过这样一条语句,可以直接得到url的HTML,不过存储的是String类型,可以通过正则进行解析,获取需要的数据。
补充4:对不同种类的URL进行分门处理
可能抓取队列中存放着不同类型的URL,对每一种爬取方案是不同的。
高大上的方法:定义抽取器
简单方法:字符串匹配
if(pageURL.contains("list")){}
else if (pageURL.contains("detail")){}
以上,就是目前遇到的一些情况,比较简单,还会再用两周。
后续内容:
(1)加代理(已经遇到封IP的情况了)、加头部文件
(2)抽取器
(3)解析Json文件、XML文件
(4)内部机制的学习调用