前言
相信很多人在使用selenium的时候都有一个困惑,就是每一次打开的浏览器实例都是不带cookie的,当有一些页面需要登录操作的时候可能就会比较麻烦,每次都需要手动登录。
其实会造成这个问题的原因是每次打开的浏览器都不会加载本地的cookie,相当于环境被隔离了。
这个问题其实也很好解决,解决的办法就是我们首先登陆一次,然后将相应的cookie记录下载,有了cookie信息后,直接加载我们缓存的cookie就可以实现免登陆了。
首先来看一下这个方案的效果,首先是京东免登陆
可以看到当我们打开新的浏览器并且访问京东首页的时候可以很快实现登录,这是因为之前已经缓存了登录的cookie了。
接着我们来看一下百度首页免登陆的效果
因为百度登录后会有一个页面的整体的变化,所以可能看的会比较清楚。
下面我们来介绍一下这个方案的实现细节。
代码简介
整体的思路前面已经介绍过了,实际上就是首先登陆一下,将cookie记录下来,然后下次登录的时候直接加载cookie就可以了。我们记录的方式就是将cookie的信息写到一个txt临时文件中。
Cookie类中我们一共需要关系四个字段,分别是下图中展示的name,value,path和domain
将cookie信息缓存的方法如下
java
public void save() {
if (driver == null) {
return;
}
log.info("走到这里了");
WebDriver.Options manage = driver.manage();
Set<Cookie> cookies = manage.getCookies();
// 检查缓存文件是否存在,如果存在则先删除再创建
if (FileUtil.exist(TMP_COOKIE_PATH)) {
FileUtil.del(TMP_COOKIE_PATH);
}
FileWriter writer = new FileWriter(TMP_COOKIE_PATH);
for(Cookie c : cookies){
StringBuilder sb = new StringBuilder();
sb.append(c.getName() + ";");
sb.append(c.getValue() + ";");
sb.append(c.getDomain() + ";");
sb.append(c.getPath() + ";\n");
log.info("获取数据=> " + sb.toString());
writer.append(sb.toString());
}
}
其中文件操作我们使用到了hutool工具库,driver是浏览器驱动实例,在执行这个方法前driver应该先被实例化。
将cookie的四个字段的数据变成字符串后写入到文件中即可,给大家展示一下缓存的百度的cookie的文件长什么样
下面说说加载cookie的方法,不知道大家之前有没有注意到,我们调用reload接口的时候,一开始的页面是没有登录的,后面才会变成登录的状态,这是因为cookie中的domian如果单独加载的话是加载不到的,我们需要首先处于当前页面中,再去加载cookie才能成功。加载的方法如下
java
public void reload() {
if (!FileUtil.exist(TMP_COOKIE_PATH)) {
log.error(TMP_COOKIE_PATH + "文件不存在");
return;
}
System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
System.setProperty("webdriver.chrome.whitelistedIps", "");
// EdgeOptions options = new EdgeOptions();
ChromeOptions options = new ChromeOptions();
//options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
options.addArguments("--remote-allow-origins=*");
// 启动浏览器
driver = new ChromeDriver(options);
// 设置最长等待时间
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get(URL);
// 加载cookies
List<String> lines = FileUtil.readLines(TMP_COOKIE_PATH, CharsetUtil.CHARSET_UTF_8);
for(int i=0; i<lines.size(); i++) {
String line = lines.get(i);
List<String> tmplist = Arrays.asList(line.split(";"));
Date expire = new Date(new Date().getTime() + 60 * 1000 * 15);
Cookie cookie = new Cookie(tmplist.get(0), tmplist.get(1), tmplist.get(2), tmplist.get(3), expire);
log.info("加载cookie=> [name=" + tmplist.get(0) + "] pvalue=" + tmplist.get(1) +
"] [domain=" + tmplist.get(2) + "] [path=" + tmplist.get(3) + "]" + " [expire=" + expire.toString() + "]");
driver.manage().addCookie(cookie);
}
driver.manage().window().maximize();
driver.get(URL);
}
注意一下,我们调用的Cookie构造函数是下面这个
其中最后一个参数expiry代表的是过期时间,这个我尝试过了,需要设置成一个大于当前时间的值,否则cookie会失效。
最后展示一下完整的代码
java
@Slf4j
@Service
public class EdgeTestService {
// private final String DRIVER_PATH = "src/main/resources/msedgedriver.exe";
private final String DRIVER_PATH = "src/main/resources/chromedriver-120.exe";
private final String TMP_COOKIE_PATH = "src/main/resources/tmpcookie.txt";
private final String URL = "https://www.baidu.com/";
// private final String URL = "https://www.jd.com/?cu=true";
private WebDriver driver = null;
public void start() {
System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
System.setProperty("webdriver.chrome.whitelistedIps", "");
// EdgeOptions options = new EdgeOptions();
ChromeOptions options = new ChromeOptions();
//options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
options.addArguments("--remote-allow-origins=*");
// 启动浏览器
driver = new ChromeDriver(options);
// 设置最长等待时间
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.manage().window().maximize();
driver.get(URL);
}
public void save() {
if (driver == null) {
return;
}
log.info("走到这里了");
WebDriver.Options manage = driver.manage();
Set<Cookie> cookies = manage.getCookies();
// 检查缓存文件是否存在,如果存在则先删除再创建
if (FileUtil.exist(TMP_COOKIE_PATH)) {
FileUtil.del(TMP_COOKIE_PATH);
}
FileWriter writer = new FileWriter(TMP_COOKIE_PATH);
for(Cookie c : cookies){
StringBuilder sb = new StringBuilder();
sb.append(c.getName() + ";");
sb.append(c.getValue() + ";");
sb.append(c.getDomain() + ";");
sb.append(c.getPath() + ";\n");
log.info("获取数据=> " + sb.toString());
writer.append(sb.toString());
}
}
public void reload() {
if (!FileUtil.exist(TMP_COOKIE_PATH)) {
log.error(TMP_COOKIE_PATH + "文件不存在");
return;
}
System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
System.setProperty("webdriver.chrome.whitelistedIps", "");
// EdgeOptions options = new EdgeOptions();
ChromeOptions options = new ChromeOptions();
//options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
options.addArguments("--remote-allow-origins=*");
// 启动浏览器
driver = new ChromeDriver(options);
// 设置最长等待时间
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get(URL);
// 加载cookies
List<String> lines = FileUtil.readLines(TMP_COOKIE_PATH, CharsetUtil.CHARSET_UTF_8);
for(int i=0; i<lines.size(); i++) {
String line = lines.get(i);
List<String> tmplist = Arrays.asList(line.split(";"));
Date expire = new Date(new Date().getTime() + 60 * 1000 * 15);
Cookie cookie = new Cookie(tmplist.get(0), tmplist.get(1), tmplist.get(2), tmplist.get(3), expire);
log.info("加载cookie=> [name=" + tmplist.get(0) + "] pvalue=" + tmplist.get(1) +
"] [domain=" + tmplist.get(2) + "] [path=" + tmplist.get(3) + "]" + " [expire=" + expire.toString() + "]");
driver.manage().addCookie(cookie);
}
driver.manage().window().maximize();
driver.get(URL);
}
public void close() {
if (driver != null) {
driver.close();
}
}
}
上述的每个方法都对应一个接口
java
@RestController
public class UserController {
@Autowired
private EdgeTestService edgeTestService;
@RequestMapping("/start")
@ResponseBody
public String start() {
edgeTestService.start();
return "success";
}
@RequestMapping("/close")
@ResponseBody
public String close() {
edgeTestService.close();
return "success";
}
@RequestMapping("/save")
@ResponseBody
public String save() {
edgeTestService.save();
return "success";
}
@RequestMapping("/reload")
@ResponseBody
public String reload() {
edgeTestService.reload();
return "success";
}
}
结语
基于上述思路就可以跳过登录环节,我觉得这个方法还是比较好的,如果你有更好的方法欢迎一起讨论交流。