使用selenium实现自动打卡
一、selenium介绍
Selenium 是最广泛使用的开源 Web UI(用户界面)自动化测试套件之一。Selenium 支持的语言包括C#,Java,Perl,PHP,Python 和 Ruby。目前,Selenium Web 驱动程序最受 Python 和 C#欢迎。 Selenium 测试脚本可以使用任何支持的编程语言进行编码,并且可以直接在大多数现代 Web 浏览器中运行。在爬虫领域 selenium 同样是一把利器,能够解决大部分的网页的反爬问题,但也不是万能的,它最明显的缺点就是速度慢。下面就进入正式的 study 阶段。
这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序是否能够很好的工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。
二、安装Chrome驱动
因为Selenium是直接运行在浏览器里的,所以使用时需要对应的Selenium驱动(本文使用的是谷歌浏览器),注意浏览器与Selenium驱动的版本一定要保持一致。
针对不同的浏览器,需要安装不同的驱动。下面列举了常见的浏览器与对应的驱动程序下载链接。
- Firefox 浏览器驱动:Firefox
- Chrome 浏览器驱动:Chrome
- IE 浏览器驱动:IE
- Edge 浏览器驱动:Edge
- PhantomJS 浏览器驱动:PhantomJS
- Opera 浏览器驱动:Opera
步骤1:确认浏览器版本
在新标签页输入 chrome://settings/
进入设置界面,然后选择 【关于 Chrome】
查看自己的版本信息。这里我的版本是98,这样在下载对应版本的 Chrome
驱动即可。
步骤2:下载对应版本的驱动
打开 Chrome驱动 。单击对应的版本。win和linux上都下载。
如果是98,则下载相应的版本。如果浏览器版本和chrome版本不一致,程序会报错。
2021年12月运行报错:此版本的ChromeDriver仅支持Chrome版本94,当前浏览器版本为96.0。所以下载96版本的。
2021年1月升级了chrome浏览器,导致2月在windows上运行代 码报错,例java提示:This version of ChromeDriver only supports Chrome version 96。
当初看到的一篇解决文章:https://chromedriver.storage.googleapis.com/index.html?path=96.0.4664.45/
windows上下载解压后的chrome驱动。D:\Program\JAVA\selenium\chromedriver_win32-v98
三、Java项目中下载和配置Selenium
教程:https://blog.csdn.net/qq_32501663/article/details/90373606
windows上如果是普通的java项目可以直接导入jar包,也可以新建springboot项目导入maven依赖。
1、可以直接导入jar包
步骤1:下载Selenium Standalone Server包:https://docs.seleniumhq.org/download/
点击版本号进行下载,下载完成将会得到一个selenium-server-4.0.0-alpha-1.jar文件;
ps:我放在 D:\Program\JAVA\selenium
步骤2:在IntelliJ idea中加载步骤1中的jar包:点击菜单栏 File –> Project Structure(快捷键Ctrl + Alt + Shift + s) ,点击 Project Structure界面左侧 的“Modules” 。在“Dependencies” 标签界面下,点击右边绿色的“+” 号,选择第一个选项“JARs or directories…” ,选择相应的 jar 包;
2、导入maven依赖
maven依赖,selenium的4.0.0版本对应chrome96以及98:
因为springboot可以直接打包,所以用maven比较方便。
四、Windows上使用Java测试selenium
https://npm.taobao.org/mirrors/chromedriver/
(一)用demo代码测试一下是否正常:
System.setProperty("webdriver.chrome.driver","D:\\Program\\JAVA\\selenium\\chromedriver_win32v3\\chromedriver.exe");//一开始我用的96版本对应的chrome驱动
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com");//记得加http不然不会出来网页
// 获取 网页的 title
System.out.println("The testing page title is: " + driver.getTitle());
成功就会跳出这个界面:
(二)配置手机浏览器
步骤1:因为chrome默认是电脑端的浏览器,而我们学校的打卡系统是只能用手机端浏览器。
//设置chromedriver的路径
path+="D:\\Program\\JAVA\\selenium\\chromedriver_win32-v98\\chromedriver.exe";
System.setProperty("webdriver.chrome.driver",path);
//配置手机浏览器
Map<String, String> mobileEmulation = new HashMap<String, String>();
mobileEmulation.put("deviceName", "Nexus 5");
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setExperimentalOption("mobileEmulation", mobileEmulation);
WebDriver driver = new ChromeDriver(chromeOptions);//如果没有配置chromeOptions,把括号里的去掉即可
步骤2:同时,使用selenium来调用chrome会跳出浏览器界面,可以设置为无界面运行。但由于网上seenium代码资料一般是python,经过了解,java要这么加:
ChromeOptions options = new ChromeOptions();
options.addArguments("headless"); //无界面参数
options.addArguments("no-sandbox"); //禁用沙盒 就是被这个参数搞了一天
WebDriver driver = new ChromeDriver(options);
//关闭浏览器 下面是关闭所有标签页,还有一个代码是 driver.close();, 关闭当前标签页
driver.quit();
五、ubuntu配置chromedriver
由于自动打卡项目需要定时运行,因此我选择部署到服务器上,而我使用的阿里云服务器系统为ubuntu。
步骤一:下载chrome浏览器
1,找到一个安装文件夹:
cd /tmp
安装chrome教程
https://blog.csdn.net/qq_40421671/article/details/108052579
2,对于谷歌Chrome32位版本,使用如下链接:
wget https://dl.google.com/linux/direct/google-chrome-stable_current_i386.deb
对于64位版本可以使用如下链接下载:
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
3,下载完后,运行如下命令安装。
sudo dpkg -i google-chrome*; sudo apt-get -f install
,4,启动
直接在终端输入如下指令
google-chrome &
5,查看google浏览器的位置:
whereis google-chrome
有一个坑,我弄了半天 : ubuntu找不到chrome二进制文件
本地java可以允许selenium和chromedriver了,而部署到服务器上则报这个问题。因为我在服务器上只配置了chromedriver,以为就行了,结果运行后我发现了问题.在我的Linux系统上,未安装Google Chrome浏览器.
java的springboot运行会报错,python也是:
我必须说异常消息“selenium.WebDriverException:unkNown error:找不到Chrome二进制文件”令人困惑.如果它告诉“未安装Chrome浏览器”或类似内容,则会更容易.
步骤二:配置无界面运行
- 安装xvfb
sudo apt-get install xvfb
这个工具是为了让我们可以无 界面运行谷歌浏览器。
同时代码里面也要写相关的配置。
步骤三:下载linux版本的chromedriver
直接去官网下载96版本的chromedriver即可。然后使用ftp拉到服务器上。记住路径。
建立软连接
- sudo mv -f chromedriver /usr/local/share/chromedriver
- sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
- sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver
- chromedriver --version #可以查看安装的版本号
写入系统变量
sudo vim /etc/profile
加入环境变量export PATH=$PATH:/urs/lib/chromium-browser/chromedriver
运行该指令使chromedriver有权限运行
chmod +x chromedriver
如果是Ubuntu系统,可能需要加上sudo来执行:sudo chmod 777 文件名
777表示读 + 写 + 执行、
步骤四:Java代码配置
Java版本参照一篇博客写的,首先依照系统不同,读取chromedriver,windows是exe文件,linux是二进制文件:
String path ="";
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")){ //微软系统
path+="D:\\Program\\JAVA\\selenium\\chromedriver_win32v3\\chromedriver.exe";
System.setProperty("webdriver.chrome.driver",path);
}else{//linux系统
path+="/home/huang/java/selenium/chromedriver";
System.out.println("os");
// System.setProperty("webdriver.chrome.driver",path);
}
//然后是配置无 界面运行chrome浏览器
chromeOptions.addArguments("--headless");
chromeOptions.addArguments("--no-sandbox");//无头浏览器
chromeOptions.addArguments("--disable-gpu");//无 界面
chromeOptions.addArguments("lang=zh_CN.UTF-8");
WebDriver driver = new ChromeDriver(chromeOptions);
步骤五:使用python代码测试chromedriver
教程:https://www.cnblogs.com/royfans/p/14172613.html
这篇文章介绍了pip安装selenium以及接下来的操作。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--disable-dev-shm-usage')
chromedriver = "/home/huang/java/selenium/chromedriver"
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chrome_options=chrome_options,executable_path=chromedriver)
driver.get("https://www.baidu.com")
print(driver.title)
driver.quit()
运行结果:
打卡代码的配置文件
虽说网上python关于selenium的资料很多。但为什么不用python,一是因为我windows上的python环境有些问题;二是个人较为熟悉java,且需要使用java进行数据库的操作。而ubuntu上的python环境配置好了,用pip指令就可以下载selenium,因此在服务器上测试时使用了python写了段简单的代码,且py文件的运行也比java简单。java使用springboot框架时,selenium可以直接在maven导入,这样就无需在服务器下载selenium,只需其他配置成功运行jar包即可。而且,在windows上,java通过下载selenium jar包和maven导入依赖两种方法都比python的selenium下载简单,为了书写代码的方便就用java写了。
六、Java中使用selenium
(一)selenium定位方法
Selenium提供了8种定位方式。
- id
- name
- class name
- tag name
- link text
- partial link text
- xpath
- css selector
这8种定位方式在Java selenium中所对应的方法为:
- findElement(By.id())
- findElement(By.name())
- findElement(By.className())
- findElement(By.tagName())
- findElement(By.linkText())
- findElement(By.partialLinkText())
- findElement(By.xpath())
- findElement(By.cssSelector())
定位方法的用法
假如我们有一个Web页面,通过前端工具(如,Firebug)查看到一个元素的属性是这样的。
<html>
<head>
<body link="#0000cc">
<a id="result_logo" href="/" onmousedown="return c({'fm':'tab','tab':'logo'})">
<form id="form" class="fm" name="f" action="/s">
<span class="soutu-btn"></span>
<input id="kw" class="s_ipt" name="wd" value="" maxlength="255" autocomplete="off">
我们的目的是要定位input标签的输入框。
-
通过id定位:
driver.findElement(By.id("kw"))
-
通过name定位:
driver.findElement(By.name("wd"))
-
通过class name定位:
driver.findElement(By.className("s_ipt"))
-
通过tag name定位:
driver.findElement(By.tagName("input"))
-
通过xpath定位,xpath定位有N种写法,这里列几个常用写法:
driver.findElement(By.xpath("//*[@id='kw']")) driver.findElement(By.xpath("//*[@name='wd']")) driver.findElement(By.xpath("//input[@class='s_ipt']")) driver.findElement(By.xpath("/html/body/form/span/input")) driver.findElement(By.xpath("//span[@class='soutu-btn']/input")) driver.findElement(By.xpath("//form[@id='form']/span/input")) driver.findElement(By.xpath("//input[@id='kw' and @name='wd']"))
-
通过css定位,css定位有N种写法,这里列几个常用写法:
driver.findElement(By.cssSelector("#kw") driver.findElement(By.cssSelector("[name=wd]") driver.findElement(By.cssSelector(".s_ipt") driver.findElement(By.cssSelector("html > body > form > span > input") driver.findElement(By.cssSelector("span.soutu-btn> input#kw") driver.findElement(By.cssSelector("form#form > span > input")
接下来,我们的页面上有一组文本链接。
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
-
通过link text定位:
driver.findElement(By.linkText("新闻") driver.findElement(By.linkText("hao123")
-
通过partialLink text定位:
driver.findElement(By.partialLinkText("新") driver.findElement(By.partialLinkText("hao") driver.findElement(By.partialLinkText("123")
关于xpaht和css的定位比较复杂,请参考: xpath语法、css选择器
(二)WebDriver常用方法
前面我们已经学习了定位元素, 定位只是第一步, 定位之后需要对这个元素进行操作, 或单击(按钮) 或 输入(输入框) , 下面就来认识这些最常用的方法。
- clear() 清除文本。
- sendKeys(*value) 模拟按键输入。
- click() 单击元素
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class BaiduDemo {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com/");
WebElement search_text = driver.findElement(By.id("kw"));
WebElement search_button = driver.findElement(By.id("su"));
search_text.sendKeys("Java");
search_text.clear();
search_text.sendKeys("Selenium");
search_button.click();
driver.quit();
}
}
clear()方法用于清除文本输入框中的内容。
sendKeys()方法模拟键盘向输入框里输入内容。 但是它的作用不仅于此, 我们还可以用它发送键盘按键, 甚至用它来指定上传的文件。
click()方法可以用来单击一个元素,前提是它是可以被单击的对象,它与 sendKeys()方法是Web页面操作中最常用到的两个方法。 其实click()方法不仅仅用于单击一个按钮,它还可以单击任何可以单击的文字/图片链接、复选框、单选框、下拉框等。
- submit()
submit()方法用于提交表单。 例如,在搜索框输入关键字之后的“回车” 操作, 就可以通过 submit()方法模拟.
WebElement search_text = driver.findElement(By.id("kw"));
search_text.sendKeys("Selenium");
search_text.submit();
- getSize() 返回元素的尺寸。
- getText() 获取元素的文本。
- getAttribute(name) 获得属性值。
- isDisplayed() 设置该元素是否用户可见。
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class BaiduDemo {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com/");
//获得百度输入框的尺寸
WebElement size = driver.findElement(By.id("kw"));
System.out.println(size.getSize());
//返回百度页面底部备案信息
WebElement text = driver.findElement(By.id("cp"));
System.out.println(text.getText());
//返回元素的属性值, 可以是 id、 name、 type 或元素拥有的其它任意属性
WebElement ty = driver.findElement(By.id("kw"));
System.out.println(ty.getAttribute("type"));
//返回元素的结果是否可见, 返回结果为 True 或 False
WebElement display = driver.findElement(By.id("kw"));
System.out.println(display.isDisplayed());
driver.quit();
}
}
打印结果:
(500, 22)
©2017 Baidu 使用百度前必读 意见反馈 京 ICP 证 030173 号 京公网安备 11000002000001 号
text
true
模拟鼠标操作
通过前面例子了解到,可以使用click()来模拟鼠标的单击操作,现在的Web产品中提供了更丰富的鼠标交互方式, 例如鼠标右击、双击、悬停、甚至是鼠标拖动等功能。在WebDriver中,将这些关于鼠标操作的方法封装在ActionChains类提供。
Actions 类提供了鼠标操作的常用方法:
- contextClick() 右击
- clickAndHold() 鼠标点击并控制
- doubleClick() 双击
- dragAndDrop() 拖动
- release() 释放鼠标
- perform() 执行所有Actions中存储的行为
百度首页设置悬停下拉菜单。
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
public class MouseDemo {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com/");
WebElement search_setting = driver.findElement(By.linkText("设置"));
Actions action = new Actions(driver);
action.clickAndHold(search_setting).perform();
driver.quit();
}
}
- import org.openqa.selenium.interactions.Actions;
导入提供鼠标操作的 ActionChains 类
- Actions(driver) 调用Actions()类,将浏览器驱动driver作为参数传入。
- clickAndHold() 方法用于模拟鼠标悬停操作, 在调用时需要指定元素定位。
- perform() 执行所有ActionChains中存储的行为, 可以理解成是对整个操作的提交动作。
七、抓包
Fiddler 下载地址 :https://www.telerik.com/download/fiddler
Fiddler 离线下载地址:https://pan.baidu.com/s/1bpnp3Ef 密码:5skw
八、Java定时任务
一、Cron详解:
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
1.Seconds Minutes Hours DayofMonth Month DayofWeek Year
2.Seconds Minutes Hours DayofMonth Month DayofWeek
每一个域可出现的字符如下:
Seconds: 可出现", - * /"四个字符,有效范围为0-59的整数
Minutes: 可出现", - * /"四个字符,有效范围为0-59的整数
Hours: 可出现", - * /"四个字符,有效范围为0-23的整数
DayofMonth :可出现", - * / ? L W C"八个字符,有效范围为0-31的整数
Month: 可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc
DayofWeek: 可出现", - * / ? L C #"四个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
Year: 可出现", - * /"四个字符,有效范围为1970-2099年
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1) :表示匹配该域的任意值,假如在Minutes域使用, 即表示每分钟都会触发事件。
(2) ?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和 DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
(3) -:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4) /:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5) ,:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6) L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7) W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一 到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份。
(8) LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9) #:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
举几个例子:
每隔5秒执行一次:"*/5 * * * * ?"
每隔1分钟执行一次:"0 */1 * * * ?"
每天23点执行一次:"0 0 23 * * ?"
每天凌晨1点执行一次:"0 0 1 * * ?"
每月1号凌晨1点执行一次:"0 0 1 1 * ?"
每月最后一天23点执行一次:"0 0 23 L * ?"
每周星期天凌晨1点实行一次:"0 0 1 ? * L"
在26分、29分、33分执行一次:"0 26,29,33 * * * ?"
每天的0点、13点、18点、21点都执行一次:"0 0 0,13,18,21 * * ?"
表示在每月的1日的凌晨2点调度任务:"0 0 2 1 * ? *"
表示周一到周五每天上午10:15执行作业:"0 15 10 ? * MON-FRI"
表示2002-2006年的每个月的最后一个星期五上午10:15执行:"0 15 10 ? 6L 2002-2006"
注意:由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?
字段 允许值 允许的特殊字符
秒 | 0-59 | , - * / | ||
---|---|---|---|---|
分 | 0-59 | , - * / | ||
小时 | 0-23 | , - * / | ||
日期 | 1-31 | , - * ? / L W C | ||
月份 | 1-12 或者 JAN-DEC | , - * / | ||
星期 | 1-7 或者 SUN-SAT | , - * ? / L C # | ||
年(可选) | 留空, 1970-2099 | , - * / |
其他一些功能:
公众号
https://blog.csdn.net/daga_a/article/details/81511676
服务器指令:
nohup java -jar yunzhanyi-v4.jar &
E:\Study_File\JavaCode\SpringbootCode\tools\yunzhanyi\target
/home/huang/java/selenium
参考文章
https://blog.csdn.net/qq_43965708/article/details/120658713?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164534809416781685337829%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164534809416781685337829&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-120658713.pc_search_result_control_group&utm_term=Selenium&spm=1018.2226.3001.4187
CentOS7 安装Selenium+chrome+chromedriver+java
https://blog.csdn.net/qq_41595144/article/details/101567571?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242.1
https://www.jianshu.com/p/71bbe8acee01
java爬取图片,虽然我不需要这个功能,但其中代码提到了根据不同系统配置chromedriver,可以借鉴: