• Java+Selenium--页面反爬虫机制,安全滑块踩过的坑


    最近工作中,要在淘宝四级页下订单并支付。淘宝的页面对自动化脚本识别控制还是挺多,短时间重复登录、下单并支付操作,会被后台检测,会在登录,四级页,订单提交页面出现安全滑块拦截。以下为最近遇到的问题踩到的坑和解决办法。

    1.关于页面识别window.navigator.webdirver属性值的问题

    当我们没有使用自动化脚本时,本地打开谷歌浏览器,在控制台输入window.navigator.webdirver时,返回的是undefined。

    当我们使用webDriver调用本地浏览器时,在控制台输入window.navigator.webdirver时,可能返回True被服务端判定为爬虫,会登录产生滑块或者登录失败。

    此时需要在代码中加入CdpCommand,同时还有ChromeOptions操作,代码一并附上

    public RemoteWebDriver init() {
            //设置property
    //driverpath为本地的chromedriver.exe的路径
    System.setProperty("webdriver.chrome.driver", driverpath); System.out.println("准备实例化ChromeOpen类"); //设置浏览器options ChromeOptions options = new ChromeOptions(); // 关闭界面上的---Chrome正在受到自动软件的控制 options.addArguments("disable-infobars"); // 允许重定向 //options.addArguments("--disable-web-security"); // 最大化 //options.addArguments("--start-maximized"); //options.addArguments("--no-sandbox"); //设置ExperimentalOption List<String> excludeSwitches = Lists.newArrayList("enable-automation"); options.setExperimentalOption("excludeSwitches", excludeSwitches); options.setExperimentalOption("useAutomationExtension", false); ChromeDriver driver = new ChromeDriver(options); //修改window.navigator.webdirver=undefined,防机器人识别机制 Map<String, Object> command = new HashMap<>(); command.put("source", "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"); driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", command); return driver; }

    2.判断页面元素是否存在,主要用于检测是不是有安全滑块(这个是真的烦,狗头ORZ)

        //判断是否存在某元素
        public boolean isJudgingElement(RemoteWebDriver remoteWebDriver, By by) {
            try {
                remoteWebDriver.findElement(by);
                return true;
            } catch (Exception e) {
                System.out.println("不存在此元素");
                return false;
            }
        }

    3.淘宝登录滑块,此处需要使用action操作,且 action.dragAndDropBy(moveButton, 258, 0).perform()为重点操作。

                //点击登录按钮
                Thread.sleep(2000);
                WebElement login = remoteWebDriver.findElement(By.xpath("//form[@id="login-form"]//div[@class="fm-btn"]/button"));
                login.click();
    
                //判断是否有滑块
                Thread.sleep(2000);
                if (isJudgingElement(remoteWebDriver, By.id("baxia-dialog-content"))) {
                    remoteWebDriver.switchTo().frame("baxia-dialog-content");
                    if (isJudgingElement(remoteWebDriver, By.id("nc_2_n1z"))) {
                        Actions action = new Actions(remoteWebDriver);
                        WebElement moveButton = remoteWebDriver.findElement(By.id("nc_2_n1z"));
                        // 移到滑块元素并悬停,不能超出框的长度,否则异常
                        action.clickAndHold(moveButton);
                        action.dragAndDropBy(moveButton, 258, 0).perform();
                        action.release();
                    }
                    remoteWebDriver.switchTo().defaultContent();
                    login.click();
                }
    
                //校验登录成功
                Thread.sleep(2000);
                WebElement userid = remoteWebDriver.findElement(By.xpath("//div[@class="site-nav-user"]/a"));
                System.out.println(userid.getText());
                if (userid.getText().equals(username)) {
                    System.out.println("淘宝网登录成功");
                }

    4.代码执行失败截图浏览器,并打印日志,退出浏览器,防止浏览器进程过多未关闭

    catch (Exception e) {
                e.printStackTrace();
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
                String currentTime = df.format(new Date());
                System.out.println(currentTime);// new Date()为获取当前系统时间
                String path = "C:\Users\Desktop\pic\Exception_" + currentTime + ".png";
                File src = ((TakesScreenshot) remoteWebDriver).getScreenshotAs(OutputType.FILE);  // 调用截图方法
                FileUtils.copyFile(src, new File(path));
                System.out.println("登录失败!");
                Thread.sleep(2000);
                remoteWebDriver.quit();
            }
    
    //浏览器退出
        public void webDriverQuit(RemoteWebDriver remoteWebDriver) {
            remoteWebDriver.quit();
            System.out.println("浏览器退出成功");
        }

    5.四级页安全滑块问题,目前四级页的安全滑块和确认订单页的安全滑块,没有比较好的方法,使用了登录的滑块方法,但是并没有效果。不过好在四级页还可以通过关闭滑块弹框,等待页面加载控件,点击立即购买,到确认订单页面。

                //打开四级页
                remoteWebDriver.get(Level4PageUrl);
                Thread.sleep(2000);
                //判断是否有安全滑块,点击关闭
                if (tblogin.isJudgingElement(remoteWebDriver, By.id("sufei-dialog-content"))) {
                    /*remoteWebDriver.switchTo().frame("sufei-dialog-content");*/
                    remoteWebDriver.findElement(By.id("sufei-dialog-close")).click();
                    /*remoteWebDriver.switchTo().defaultContent();*/
                    //页面缓存
                    Thread.sleep(10000);
                }
    
                //点击立即购买按钮
                remoteWebDriver.findElement(By.id("J_LinkBuy")).click();
                Thread.sleep(2000);

    6.确认订单页面的安全滑块(参照账号登录方法,不过滑块验证失败,待解决,有解决方案的大佬多多指教,感谢)

                //订单页面滑块判断
                if (tblogin.isJudgingElement(remoteWebDriver, By.id("nc_1_n1z"))) {
                    Actions action = new Actions(remoteWebDriver);
                    WebElement moveButton = remoteWebDriver.findElement(By.id("nc_1_n1z"));
                    // 移到滑块元素并悬停,不能超出框的长度,否则异常
                    action.clickAndHold(moveButton);
                    action.dragAndDropBy(moveButton, 258, 0).perform();
                    action.release();
                    Thread.sleep(2000);
                    if(!tblogin.isJudgingElement(remoteWebDriver, By.linkText("提交订单"))){
                        //试图二次刷新页面,操作安全滑块
                        String currentUrl = remoteWebDriver.getCurrentUrl();
                        remoteWebDriver.get(currentUrl);
                        Thread.sleep(2000);
                        action = new Actions(remoteWebDriver);
                        moveButton = remoteWebDriver.findElement(By.id("nc_1_n1z"));
                        // 移到滑块元素并悬停,不能超出框的长度,否则异常
                        action.clickAndHold(moveButton);
                        action.dragAndDropBy(moveButton, 258, 0).perform();
                        action.release();
                        Thread.sleep(2000);
                    }
                }

    7.重头戏!好家伙,这玩意卡了我两天,支付页面,输入密码提交支付。开始的思路,页面的密码输入框不可点击,想通过js语句去修改html的css属性,达到元素可以定位的效果。无奈,不论怎么修改,都无法在页面生效,这里不得不给支付宝的开发大大点赞。

     

    这个思路不行,就想别的解决方案。发现从订单提交页面提交成功后,跳转到支付页面,光标是自动定位到密码的第一个输入框的,而且元素的属性是visibility: visible,并且输入第一个数字后,光标自动移到第二个输入框。然后就想,是不是有方法能够获取当前光标,直

    接去模拟键盘操作。在网上找了很多帖子,奈何基本都是python的帖子,用的是keyboard类的方法。就在绝望准备推倒java,拿起python工具之前,google了一下,发现可以使用action的思路。

                //输入支付密码
                for (int i = 0; i < payPassword.length(); i++) {
                    char c = payPassword.charAt(i);
                    String password = String.valueOf(c);
                    Actions action = new Actions(remoteWebDriver);
                    action.sendKeys(password).build().perform();
                    action.clickAndHold();
                    action.release();
                    /*String path = picpath + i + ".png";
                    File src = ((TakesScreenshot) remoteWebDriver).getScreenshotAs(OutputType.FILE);  // 调用截图方法
                    FileUtils.copyFile(src, new File(path));*/
                }
                Thread.sleep(1000);
                remoteWebDriver.findElement(By.id("J_authSubmit")).click();
                Thread.sleep(5000);
    
                //付款成功校验
                String resp = remoteWebDriver.findElement(By.xpath("//div[@id="J_AmountList"]/h2")).getText();
    
                if ("您已成功付款".equals(resp)) {
                    System.out.println("订单支付成功");
                    String currentUrl = remoteWebDriver.getCurrentUrl();
                    System.out.println(currentUrl);
                    String[] orderIdArray1 = currentUrl.split("bizOrderId=");
                    String orderIdString = orderIdArray1[1];
                    String[] orderIdArray2 = orderIdString.split("&");
                    orderId = orderIdArray2[0];
                    System.out.println("订单编号orderId:" + orderId);
                    SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
                    currentTime = df.format(new Date());
                    String path = picpath + currentTime + "_orderCreate_" + orderId + ".png";
                    File src = ((TakesScreenshot) remoteWebDriver).getScreenshotAs(OutputType.FILE);  // 调用截图方法
                    FileUtils.copyFile(src, new File(path));
                    tblogin.webDriverQuit(remoteWebDriver);
                }

    8.将订单号,下单时间等信息保存到excel中

    public static void createExcelxlsx(String path) throws Exception {
            //创建excel对象
            XSSFWorkbook wb = new XSSFWorkbook();
            //用文件对象创建sheet对象
            XSSFSheet sheet = wb.createSheet("sheet1");
            //创建单元格样式
            CellStyle cellStyle = wb.createCellStyle();
            //设置表头
            XSSFRow rowInit = sheet.createRow(0);
            Cell cell1 = rowInit.createCell(0);
            Cell cell2 = rowInit.createCell(1);
            Cell cell3 = rowInit.createCell(2);
            cell1.setCellValue("行号");
            cell2.setCellValue("订单编号");
            cell3.setCellValue("创建时间");
            FileOutputStream outputInit = new FileOutputStream(path);
            wb.write(outputInit);
            outputInit.flush();
            outputInit.close();
        }
    
        public static void saveExcelxlsx(String path, int i, String value, String time) throws Exception {
            XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(path));
            XSSFSheet sheet = wb.getSheet("sheet1");
            //写订单数据
            //用sheet对象创建行对象
            XSSFRow row = sheet.createRow(i + 1);
            //构造数据
            List<Object> list = new ArrayList<>();
            list.add(i + 1);
            list.add(value);
            list.add(time);
            int length = list.size();
    
            for (int n = 0; n < length; n++) {
                FileOutputStream output = new FileOutputStream(path);
                //用行对象创建单元格对象Cell
                Cell cell = row.createCell(n);
                //用cell对象读写。设置excel工作表值
                cell.setCellValue(list.get(n).toString());
                wb.write(output);
                output.flush();
                output.close();
            }
        }
    
        public static void main(String[] args) throws Exception {
            for (int i = 0; i < 10; i++) {
                HashMap<String, String> hashMap = tbOrderCreate();
                Iterator it = hashMap.keySet().iterator();
                String v = "";
                String t = "";
                while (it.hasNext()) {
                    v = it.next().toString();
                    t = hashMap.get(v);
                }
                if (!("".equals(v))) {
                    File file = new File(excelpath);
                    if (!file.exists()) {
                        createExcelxlsx(excelpath);
                        saveExcelxlsx(excelpath, i, v, t);
                    } else {
                        saveExcelxlsx(excelpath, i, v, t);
                    }
                }
            }
        }

     

  • 相关阅读:
    四则运算实现
    第四周例行报告
    代码规范,结对要求
    第三周例行报告
    第三周作业3功能测试
    第二周例行报告
    第一次作业汇总
    2017/2/24:Maven的pom jar war的区别
    oracle的常用99条语句
    2017/2/21:配置自己的中文乱码拦截器
  • 原文地址:https://www.cnblogs.com/KevinFeng/p/15138360.html
Copyright © 2020-2023  润新知