当前位置:网站首页>Webmagic+selenium+chromedriver+jdbc垂直抓取数据。
Webmagic+selenium+chromedriver+jdbc垂直抓取数据。
2022-07-27 16:28:00 【黑暗料理界的扛把子】
新手小白入手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按照一定的顺序能够拼接成页面当中显示的图片,不过这个图片在当中是缺少一块的,我们根据拼接成的图片找到当中颜色与其他地方不一样的一块,然后根据这个块的大小计算,我们需要移动页面当中小块需要移动的距离。
在实际当中往往我们需要考虑更多的东西,页面当中小块移动的距离,小块完成移动需要的时间,针对同一滑块我们往往为了掩饰机器,需要放慢速度,多设计几种滑块速度。
边栏推荐
- Big enemies, how to correctly choose the intended enterprises in the new testing industry?
- Latex使用--subfigure竖排图形
- Performance analysis of continuous time systems (2) - second order system performance improvement methods PID, PR
- Kinect for Unity3D——BackgroundRemovalDemo学习
- mysql学习笔记(1)——变量
- 用函数在Excel中从文本字符串提取数字
- `this.$ Emit ` the child component passes multiple parameters to the parent component
- 进行接口测试时,连接数据库,对数据源进行备份、还原、验证操作
- Double insurance for line breaking
- win10小技巧(1)——转移桌面位置
猜你喜欢

一篇让你掌握线程和线程池,还解决了线程安全问题,确定不看看?

IDEA成功连接Database但不显示表怎么办

阿里云对象存储OSS的开通和使用

Kinect for Unity3d----KinectManager

Basic use of Nacos (1) - getting started

自控原理学习笔记-系统稳定性分析(1)-BIBO稳定及Routh判据

What if idea successfully connects to the database without displaying the table

Mongodb learning notes (1) - install mongodb and its related configurations

Performance analysis of continuous time system (1) - performance index and first and second order analysis of control system

Kinect2 for Unity3D——AvatarDemo学习
随机推荐
kettle 合并记录 数据减少
kettle引用外部脚本完成电话号码清洗、去重缩进
Performance analysis of continuous time systems (2) - second order system performance improvement methods PID, PR
kettle EXCEL 累计输出数据
kettle 分列、合并记录
Mongodb learning notes (1) - install mongodb and its related configurations
Docker - docker installation, MySQL installation on docker, and project deployment on docker
利用 Fastjson json (简单粗暴版)
Nacos基本概念和单机部署
Unity显示Kinect捕获的镜头
连续时间系统的性能分析(2)-二阶系统性能改善方式PID,PR
Browser rendering principle analysis suggestions collection
IDEA成功连接Database但不显示表怎么办
2022 preparation for autumn recruitment 10W word interview sketch PDF version, with operating system and computer network interview questions
大冤种们,新进测试行业,如何正确选择意向企业?
asp. Net experience
收下这份实操案例,还怕不会用Jmeter接口测试工具
Down sampling - signal phase and aliasing
自控原理学习笔记-系统稳定性分析(2)-环路分析及Nyquist-Bode判据
Nacos cluster deployment - high availability guarantee