Java Selenium4 ChromeDriver获取指定的POST请求
前言
最近项目上需要去找某个网站对应的请求数据,但是这个网站有个奇怪的反爬机制,你如果直接去请求这个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);
// 监听最后一次匹配的请求,获取对应的requestId
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();