Java Selenium4 ChromeDriver获取指定的POST请求

发布时间 2023-04-21 15:54:07作者: 爱摸鱼冉先生

前言

最近项目上需要去找某个网站对应的请求数据,但是这个网站有个奇怪的反爬机制,你如果直接去请求这个url(listPro)是获取不到数据的,它会返回一段加密后的js代码过来,如果在浏览器上执行也不行,需要在这个网站上执行,这段代码主要是加密设置一个cookie,我在浏览器上复制这个cookie后,可以在后端执行一段时间,过期了就不行
这就很头疼了,我想的是在浏览器上执行后再返回,但是这段js也需要在这个网站上执行,造成了我无法使用这个接口的问题,所以我研究了一段时间,发现了这个爬取方法
类似的爬取方法数不胜数,我主要是不想把它爬下来放到数据库里面,其它的那些考虑就不在话下了

参考文档

Selenium官方文档
Stack overflow : how to get http response code using selenium webdriver
Stack overflow : chromedevtools in selenium waiting for response bodies

代码

先看下pom.xml,网上有很多人不推荐使用Selenium4+版本,但我觉得没多大影响
还有一点是为什么我引入了这么多包,如果只引入第一个的话,后面会遇到版本冲突的问题

<dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chromium-driver</artifactId>
            <version>4.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-api</artifactId>
            <version>4.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>4.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-remote-driver</artifactId>
            <version>4.8.3</version>
        </dependency>

然后就是核心代码了

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v111.network.Network;
import org.openqa.selenium.devtools.v111.network.model.RequestId;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class CkcestHandler {

  private static String getHtmlByChrome(String queryExpression){
    System.getProperties().setProperty("webdriver.chrome.driver", "E:\\Development\\chromeDriver\\chromedriver.exe");
    ChromeDriver chromeDriver = new ChromeDriver();
    chromeDriver.get("https://www.example.com");
    DevTools devTools = chromeDriver.getDevTools();
    devTools.createSession();
    devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

    //切换
    chromeDriver.findElement(By.xpath("/html/body/div[3]/div[2]/div[1]/a[2]")).click();

    //点击全选CheckBox
    chromeDriver.findElement(By.id("dbSelectAll")).click();

    //传入表达式
    chromeDriver.findElement(By.id("expertSearchTextarea")).sendKeys(queryExpression);


    // 监听最后一次匹配的请求,对应的response body
    String compareUrl = "https://www.example.com/listPro";
    AtomicReference<RequestId> requestId = new AtomicReference<>();
    devTools.addListener(Network.responseReceived(), responseReceived -> {
      if(responseReceived.getResponse().getUrl().equals(compareUrl) && responseReceived.getResponse().getStatus() == 200){
        requestId.set(responseReceived.getRequestId());
      }
    });

    // 点击专业搜索 -> 发起请求
    chromeDriver.findElement(By.id("expertSearchBtn")).click();

    // 等待获取到数据的html发生变化,超时时间为30秒
    ExpectedCondition<List<WebElement>> listExpectedCondition = ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath("//*[@id=\"list_content_warp\"]/div"), 0);
    new WebDriverWait(chromeDriver, Duration.ofSeconds(30).getSeconds()).until(listExpectedCondition);

    // 获取开发者工具中的返回结果
    String  responseBody = devTools.send(Network.getResponseBody(requestId.get())).getBody();

    chromeDriver.quit();
    return responseBody;
  }
}

或者可以输出HTML格式,这种方式就不需要devtools了

Object executeScriptResult = chromeDriver.executeScript("return document.evaluate(\"//*[@id=\\\"center_main\\\"]\",document).iterateNext().innerHTML;");

String html = executeScriptResult.toString();