Webmagic+selenium+chromedriver+jdbc垂直抓取数据。

新手小白入手selenium+chromedriver爬虫,爬取各种网站之后觉得只要能看到的都能抓到是真方便,就是效率低了点。所以开始加点东西提高一下爬虫效率。对我来说最直接的方法就是单线程变多线程~~~

1、webmagic爬取数据  规则

框架

Selenium

webmagic

抓取规则

针对单个或者一类页面制定爬虫规则

针对多类页面制定多种爬虫规则垂直爬取

线程

单线程

多线程

解析json

需要其他jar辅助

内置json解析工具

页面抽取工具

内置页面抽取规则

内置页面抽取规则

断电重续

不存在

存在

IP代理池

需要自己写

0.4版本之后开始出现内置代理池(性能不稳定),0.6版本之后能够自己编写IP代理池

以往的爬虫当中需要针对某一个或者一类页面单独制定爬虫规则,webmagic也是如此,不同的是webmagic是垂直爬取。

什么是垂直爬取呢?来看个图:

       这是树形图与webmagic的抓取逻辑类似,我们可以把“语法树根节点”理解为我们抓取的起始页面,在这个页面我们除了可以抓取需要的数据,还能获得子页面的链接(if语句、调用方法),我们将子页面的链接加入待抓取队列,那么我们接下来就会对子页面当中的信息进行抓取,依次类推我们可以获得不同深度(主页面当中的子页面深度为1,以此类推)页面当中的数据,同时能够不断的在抓取队列当中添加信息。

       我们在抓取队列当中不断添加需要抓取的页面链接,但是各个深度的页面抓取规则和需要的数据也是不一样的,按照以往我们需要写很多的程序,webmagic通过Page对象解决这一个问题,我们在Page对象当中对抓取页面进行分类,然后再匹配对应的抓取规则。

2、webmagic框架搭建

      2.1 mavan搭建 

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-core</artifactId>
    <version>0.7.3</version>
</dependency>
<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-extension</artifactId>
    <version>0.7.3</version>
</dependency>

      2.2  jar包搭建

       需要的jar太多了去我的百度网盘下载吧(提取码:p5z6)

3、创建爬虫项目

      做爬虫总是要寻找示例的,webmagic适合爬取含有至少两层深度的数据源,或者是含有众多子页面的数据源。

      最近在整理数据源的盘口数据那么我就拿其中一个作为爬取示例。

       首先分享一下目录结构(web工程)

      别的不多说了直接上代码

package cyt.selenium;


import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import pankou.dao.ALLcharDao;
import pankou.pojo.AllChar;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;

public class seleniumXxdj implements PageProcessor  {

	/**
	 * vpgame盘口数据抓取小程序<br>

	 * @date 2018-8-20
	 * @website http://www.vpgame.com/###
	 * @author jingsheng
	 * @game lol
	 */
	
	// 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
    private Site site = Site.me().setRetryTimes(10).setSleepTime(1000).addHeader("Accept-Encoding", "/");
    private static int count =0;
	
	
	public void process(Page page) {
	
		//加载webdriver驱动
		System.setProperty("webdriver.chrome.driver",  "D:/cyt_down/selenium/chromedriver.exe");
		WebDriver driver = new ChromeDriver();
		
		String nowUrlStr = page.getUrl().toString() ;
		
		if(nowUrlStr.indexOf("game")!=-1){
			driver.get(nowUrlStr);
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			int matchNumber = driver.findElements(By.className("match")).size();
			System.out.println("目前一共有 " + matchNumber + "条数据。准备进行筛选~~~~");
			for(int a=0;a<matchNumber;a++){

				try {
					WebElement matchList = driver.findElements(By.className("match")).get(a);
					System.out.println("准备抓取字段~~~");
					
					String url = "" ;String matchCLass ="";String gameStateStr="";
					String LeagueName ="";String LeaguePic="";
					String VisitPic = "";String VisitName = "" ;String HomeScore = "";
					String VisitScore = "";String HomeName  ="";String HomePic = "";
					String gameStatetest =""; String itemStaus = "" ;
					
					String firstDivStr = matchList.findElement(By.xpath("./div[1]")).getText();
					int trueNum = 1 ;
					if(firstDivStr.length()>2){
						System.out.println("比赛正在进行中");
						trueNum = 0 ;
					}
					
					try {
						gameStatetest = matchList.findElement(By.xpath("./div["+(1+trueNum)+"]")).getText();
						System.out.println("gameStatetest" + gameStatetest);
					} catch (Exception e) {
						System.err.println("gameStatetest 不存在");
						continue;
					}
					
					try {
						url = matchList.findElement(By.xpath("./div["+(6+trueNum)+"]/ul/li[2]/a")).getAttribute("href");
						System.out.println("url" + url);
					} catch (Exception e) {
						System.err.println("url 不存在");
						e.printStackTrace();
						continue;
					}
					
					try {
						matchCLass = matchList.findElement(By.xpath("./div["+(6+trueNum)+"]/ul/li[2]/a")).getAttribute("class");
						System.out.println("matchCLass  " + matchCLass);
					} catch (Exception e) {
						System.out.println("matchCLass 不存在");
					}
					
					try {
						String gameStateStr_test = matchList.findElement(By.xpath("./div["+(7+trueNum)+"]")).getText();
						gameStateStr = judgmentGameStateStr(gameStateStr_test);
						itemStaus =  judgmentItemStaus(gameStateStr_test);
						System.out.println("gameStateStr  " + gameStateStr);
					} catch (Exception e) {
						System.out.println("gameStateStr 不存在");
					}
					
					try {
						LeagueName = matchList.findElement(By.xpath("./div["+(5+trueNum)+"]/div")).getText().replaceAll("\\s*", "");
						System.out.println("LeagueName  " + LeagueName);
					} catch (Exception e) {
						System.out.println("LeagueName 不存在");
					}
					
					
					try {
						VisitPic = matchList.findElement(By.xpath("./div["+(4+trueNum)+"]/div/span[1]/img")).getAttribute("src");
						System.out.println("VisitPic  " + VisitPic);
					} catch (Exception e) {
						System.out.println("VisitPic 不存在");
					}
					
					try {
						VisitName = matchList.findElement(By.xpath("./div["+(4+trueNum)+"]/div/span[2]")).getText();
						System.out.println("VisitName  " + VisitName);
					} catch (Exception e) {
						System.out.println("VisitName 不存在");
					}
					
					try {
						HomeScore = matchList.findElement(By.xpath("./div["+(2+trueNum)+"]/div[2]")).getText();
						System.out.println("HomeScore  " + HomeScore);
					} catch (Exception e) {
						System.out.println("HomeScore 不存在");
					}
					
					try {
						VisitScore = matchList.findElement(By.xpath("./div["+(4+trueNum)+"]/span")).getText();
						System.out.println("VisitScore  " + VisitScore);
					} catch (Exception e) {
						System.out.println("VisitScore 不存在");
					}
					
					try {
						HomeName = matchList.findElement(By.xpath("./div["+(2+trueNum)+"]/div[1]/span[1]")).getText();
						System.out.println("HomeName  " + HomeName);
					} catch (Exception e) {
						System.out.println("HomeName 不存在");
					}
					
		
				

					count = count +1 ;
				
				} catch (Exception e) {
					e.printStackTrace();
				}
			
			}
		}else if(nowUrlStr.indexOf("match")!=-1) {
			//抓取详情页信息
			driver.get(nowUrlStr);
			
			String startTime = ""; String fullScore= "";
			boolean next = false;
			//1、判断是否存在盘口数据
			try {
				String pankouStr = driver.findElement(By.className("matchRight")).findElement(By.xpath("./div[1]/p")).getText();
				next = true ;
			} catch (Exception e) {
				System.err.println("不存在盘口数据");
			}
			
			//2、遍历盘口数据,进行存储
			if(next==true){
				try {
					String test = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div[1]/div[3]/p")).getText();
					startTime = judgmentStartTime(test);
					
					fullScore = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div[1]/div[3]/div[1]/span")).getText();
					
					WebElement matchRight = driver.findElement(By.className("matchRight"));
					List<WebElement> list = driver.findElement(By.className("matchRight"))
						   	  .findElement(By.xpath("./div[1]"))
							  .findElements(By.tagName("dl"));
					System.out.println("目前一共拥有 " + list.size() +"条数据");
					for(int a=0;a<list.size();a++){
						String itemName ="" ; String oddsRate = "" ;
						if(list.size() == 1){
							itemName = matchRight.findElement(By.xpath("./div[1]/dl/dt")).getText();
							int aNum = matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd")).findElements(By.tagName("a")).size();
							if(aNum==3){
								oddsRate = matchRight.findElement(By.xpath("./div[1]/dl/dd/a[1]/span[2]")).getText() +":"+ 
										   matchRight.findElement(By.xpath("./div[1]/dl/dd/a[2]/span[2]")).getText() +":"+
										   matchRight.findElement(By.xpath("./div[1]/dl/dd/a[3]/span[2]")).getText();
							}else {
								oddsRate = matchRight.findElement(By.xpath("./div[1]/dl/dd/a[1]/span[2]")).getText() +":"+ 
										   matchRight.findElement(By.xpath("./div[1]/dl/dd/a[2]/span[2]")).getText();
							}
							
						}else {
							itemName = matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dt")).getText();
							int aNum = matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd")).findElements(By.tagName("a")).size();
							if(aNum==3){
								oddsRate = matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd/a[1]/span[2]")).getText() +":"+ 
										   matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd/a[2]/span[2]")).getText() +":"+
										   matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd/a[3]/span[2]")).getText();
							}else {
								oddsRate = matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd/a[1]/span[2]")).getText() +":"+ 
										   matchRight.findElement(By.xpath("./div[1]/dl["+(a+1)+"]/dd/a[2]/span[2]")).getText();
							}
							
						}
						
					
						}else{
							System.out.println("插入第"+(a+1)+"条盘口数据~~~");
							//把对象存入数据库
							int selectPankouResult = new ALLcharDao().selectXxdjPankou(allChar, rs);
							if(selectPankouResult==1){
								System.out.print("数据库当中已经含有该盘口数据--->");
								new ALLcharDao().updateXx(allChar);
								System.out.println("    更新成功");
							}else{
								new ALLcharDao().add(allChar);
								System.out.println("盘口数据改变,更新");
							}
							
						}
						
						//把对象输出到控制台
						System.out.println(allChar);

						count = count +1 ;
						
					}
				
				} catch (Exception e) {
					System.err.println("盘口数据出错");
					e.printStackTrace();
				}
			}else{
				String test = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div[1]/div[3]/p")).getText();
				startTime = judgmentStartTime(test);
				
				fullScore = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div[1]/div[3]/div[1]/span")).getText();
				
				
				

				count = count +1 ;
			}
			
		}
		
		driver.quit();
    }
	
	public Site getSite() {
			return this.site;
	}

	@SuppressWarnings("deprecation")
	public static <Request> void main(String[] args) {
		 long startTime, endTime;
        System.out.println("开始爬取...");
        startTime = System.currentTimeMillis();
        System.out.println(startTime);
        
        List<String> startUrls =new  ArrayList<String>();
        startUrls.add("https://www.xxdianjing.com/game11.html");
        startUrls.add("https://www.xxdianjing.com/game24.html");
        startUrls.add("https://www.xxdianjing.com/game65.html");
        startUrls.add("https://www.xxdianjing.com/game254.html");
        startUrls.add("https://www.xxdianjing.com/game205.html");
        
        Spider.create(new seleniumXxdj())
              .startUrls(startUrls)
              .thread(5)
              .addPipeline(new ConsolePipeline())
              .run();
        endTime = System.currentTimeMillis();
        
        System.out.println("爬取结束,耗时约" + ((endTime - startTime) / 1000) + "秒,抓取了"+count+"条记录");

	}
	

	public static String judgmentCnName (String str){
		String newStr = "" ;
		if(str.indexOf("game11.html")!=-1){
			return newStr= "英雄联盟";
		}else if(str.indexOf("game24.html")!=-1){
			return newStr= "刀塔2";
		}else if(str.indexOf("game65.html")!=-1){
			return newStr= "守望先锋";
		}else if(str.indexOf("game254.html")!=-1){
			return newStr= "王者荣耀";
		}else if(str.indexOf("game205.html")!=-1){
			return newStr= "反恐精英";
		}else{
			return newStr ;
		}
	}
	
	public static String judgmentEnName (String str){
		String newStr = "" ;
		if(str.indexOf("game11.html")!=-1){
			return newStr= "League of Legends";
		}else if(str.indexOf("game24.html")!=-1){
			return newStr= "Dota2";
		}else if(str.indexOf("game65.html")!=-1){
			return newStr= "OW";
		}else if(str.indexOf("game254.html")!=-1){
			return newStr= "King of Glory";
		}else if(str.indexOf("game205.html")!=-1){
			return newStr= "CSGO";
		}else{
			return newStr ;
		}
	}
	
	public static String judgmentGameId (String str){
		String newStr = "" ;
		if(str.indexOf("game11.html")!=-1){
			return newStr= "002";
		}else if(str.indexOf("game24.html")!=-1){
			return newStr= "003";
		}else if(str.indexOf("game65.html")!=-1){
			return newStr= "006";
		}else if(str.indexOf("game254.html")!=-1){
			return newStr= "001";
		}else if(str.indexOf("game205.html")!=-1){
			return newStr= "004";
		}else{
			return newStr ;
		}
	}
	
	public static String judgmentGameState (String str){
		String newStr = "" ;
		if(str.indexOf("进行中")!=-1){
			return newStr= "1";
		}else{
			return newStr= "0" ;
		}
	}
	
	public static String judgmentGameStateStr (String str){
		String newStr = "" ;
		if(str.indexOf("距竞猜截止还有")!=-1) {
			return newStr= "比赛未开始" ;
		}else if(str.indexOf("暂无竞猜或竞猜未开始")!=-1) {
			return newStr= "比赛未开始" ;
		}else if(str.indexOf("竞猜截止时间已到")!=-1) {
			return newStr= "比赛进行中" ;
		}else {
			return newStr= "" ;
		}
	}
	
	public static String judgmentItemStaus (String str){
		String newStr = "" ;
		if(str.indexOf("进行中")!=-1){
			return newStr= "已结束";
		}else{
			return newStr= "竞猜中" ;
		}
	}
	
	public static String judgmentStartTime (String str){
		try {
			String newStr = str.split(" ")[0] +" " + str.split(" ")[1];
			return newStr ;
		} catch (Exception e) {
			return "" ;
		}
	}
	
}

4、程序分析

       webmagic结合selenium确实似的爬虫效率大大提升,可是也让潜在问题爆发出来,似的一些东西成为必不可少的,就比如说IP代理池和网站反爬虫机制(极验验证、验证码、页面数据加密)。

        webmagic从0.4.0版本开始,支持Http代理。因为场景的多样性,代理这部分的API一直处于不稳定状态,但是因为需求确实存在,所以webmagic会继续支持代理部分的完善。在0.6.0版本后,允许实现自己的代理池,通过扩展接口ProxyPool来实现。目前webmagic的代理池逻辑是:轮流使用代理池中的IP,如果某个IP失败超过20次则增加两小时的重用时间,具体实现可以参考SimpleProxyPool。

       这里我给一下添加IP代理的方法,不过由衷感叹自己抓的代理池真心不好用

//添加单个IP
site.setHttpProxy(new HttpHost("101.101.101.101",8888))
    .setUsernamePasswordCredentials(new UsernamePasswordCredentials("username","password"))
//添加多个IP
List<String[]> poolHosts = new ArrayList<String[]>();
poolHosts.add(new String[]{"username","password","101.101.101.101","8888"});
poolHosts.add(new String[]{"username","password","102.102.102.102","8888"});
//httpProxyList输入是IP+PORT, isUseLastProxy是指重启时是否使用上一次的代理配置
site.setHttpProxyPool(poolHosts,false);

       极验验证说简单也是简单,说难也是难。说一下我处理极验验证的方法。

       极验验证一半来说是在页面当中存在20张Img,这20张Img按照一定的顺序能够拼接成页面当中显示的图片,不过这个图片在当中是缺少一块的,我们根据拼接成的图片找到当中颜色与其他地方不一样的一块,然后根据这个块的大小计算,我们需要移动页面当中小块需要移动的距离。

       在实际当中往往我们需要考虑更多的东西,页面当中小块移动的距离,小块完成移动需要的时间,针对同一滑块我们往往为了掩饰机器,需要放慢速度,多设计几种滑块速度。

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值