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

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

1、webmagic爬取数据  规则

框架

Selenium

webmagic

抓取规则

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

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

线程

单线程

多线程

解析json

需要其他jar辅助

内置json解析工具

页面抽取工具

内置页面抽取规则

内置页面抽取规则

断电重续

不存在

存在

IP代理池

需要自己写

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

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

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

Webmagic+selenium+chromedriver+jdbc垂直抓取数据。_第1张图片

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

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

2、webmagic框架搭建

      2.1 mavan搭建 


    us.codecraft
    webmagic-core
    0.7.3


    us.codecraft
    webmagic-extension
    0.7.3

      2.2  jar包搭建

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

3、创建爬虫项目

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

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

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

Webmagic+selenium+chromedriver+jdbc垂直抓取数据。_第2张图片

      别的不多说了直接上代码

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盘口数据抓取小程序
* @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;a2){ 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 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"); 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 void main(String[] args) { long startTime, endTime; System.out.println("开始爬取..."); startTime = System.currentTimeMillis(); System.out.println(startTime); List startUrls =new ArrayList(); 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 poolHosts = new ArrayList();
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按照一定的顺序能够拼接成页面当中显示的图片,不过这个图片在当中是缺少一块的,我们根据拼接成的图片找到当中颜色与其他地方不一样的一块,然后根据这个块的大小计算,我们需要移动页面当中小块需要移动的距离。

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

 

你可能感兴趣的:(java,爬虫,webmagic,selenium,垂直爬虫)