最近自己在做一个项目使用Selenium抓取数据,发现升级Google Chrome 84版本会出现 被检测出来使用 就不给你返回数据,导致无法使用,抓狂了一段时间没有解决方案,以下都是亲测成功总结,百度搜索都是千遍一律的结果,有许多坑。
防止网站检测出Selenium的window.navigator.webdriver属性
1.升级Selenium 版本
<!-- selenium解析器 -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0-alpha-6</version>
</dependency>
java.lang.NoSuchMethodError: 'byte[] kotlin.collections.ArraysKt.copyInto
升级版本的时候会遇到包版本冲突的问题,解决方法:
<!-- https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.3.70</version>
</dependency>
2. 使用官方插件CDP命令 屏蔽window.navigator.webdriver属性值
ChromeOptions options =new ChromeOptions();
//不提示“Chrome正受到自动测试软件控制”
options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation") );
options.setExperimentalOption("useAutomationExtension", false);
Map map =new HashMap();
map.put("source","Object.defineProperties(navigator, {webdriver:{get:()=>undefined}})");
driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument",map);
3. ChromeDriver 对应本地浏览器的版本
selenium是一个自动化网页测试业务流程工具,也可以用来爬取网页数据。
谷歌驱动下载 ChromeDriver 2.35
我本地Google Chrome 84.0.4147.125(正式版本) (64 位)
也可以用,但是selenium升级后用不了CDP命令。
http://npm.taobao.org/mirrors/chromedriver/
下载chromeDriver:http://chromedriver.storage.googleapis.com/index.html
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
selenium 依赖了com.google.guava 25.0-jre注意重复依赖问题
重复依赖报错:
java.lang.IllegalAccessError: tried to access method com.google.common.util.concurrent.SimpleTimeLimiter.<init>(Ljava/util/concurrent/ExecutorService;)V
解决方法 找出低版本的另一个依赖排除com.google.guava依赖:
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
我的冲突就是io.springfox包含了com.google.guava 20.0,该项目的pom.xml依赖下加上以上的语句来排除依赖
Selenium 3.0使用firefox
https://github.com/mozilla/geckodriver/releases
###java###
private static WebDriverdriver;
private static ChromeDriverServiceservice;
public static void createAndStartService() {
service =new ChromeDriverService.Builder()
.usingDriverExecutable(new File("C:\\Program Files (x86)\\webDriver\\chromedriver.exe"))
.usingAnyFreePort()
.build();
try {
service.start();
}catch (IOException e) {
e.printStackTrace();
}
}
public static void createDriver(URL url, String urlPath){
driver =new RemoteWebDriver(url, DesiredCapabilities.chrome());
//driver.get(urlPath); //打开一个页面访问
try {
/**
* WebDriver自带了一个智能等待的方法。 dr.manage().timeouts().implicitlyWait(arg0, arg1);
* Arg0:等待的时间长度,int 类型 ; Arg1:等待时间的单位 TimeUnit.SECONDS 一般用秒作为单位。
*/
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前浏览器的信息
System.out.println("Title:" +driver.getTitle());
System.out.println("currentUrl:" +driver.getCurrentUrl());
}
private void createDriver(URL url, String urlPath){
try {
if(url ==null){
url=service.getUrl();
}
ChromeOptions options =new ChromeOptions();
//不提示“Chrome正受到自动测试软件控制”
options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
options.setExperimentalOption("useAutomationExtension", false);
//driver = new ChromeDriver(service, options);
//driver = new RemoteWebDriver(url, DesiredCapabilities.chrome());
//不加载图片,加快访问速度
Map prefs =new HashMap();
prefs.put("profile.managed_default_content_settings.images", 2);
options.setExperimentalOption("prefs", prefs);
//使用本地的Google浏览器,一次只能打开一个
options.addArguments("user-data-dir=C:/Users/Administrator/AppData/Local/Google/Chrome/User Data");
driver =new ChromeDriver(service, options);
//解决,对window.navigator.webdriver的检测机制
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("Object.defineProperties(navigator, {webdriver:{get:()=>undefined}});");
if(StringUtils.isNotEmpty(urlPath)) {
driver.get(urlPath);
}
/**
* WebDriver自带了一个智能等待的方法。 dr.manage().timeouts().implicitlyWait(arg0, arg1);
* Arg0:等待的时间长度,int 类型 ; Arg1:等待时间的单位 TimeUnit.SECONDS 一般用秒作为单位。
*/
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}catch (Exception e) {
e.printStackTrace();
}
}
参数设置
ChromeOptions options =new ChromeOptions();
//不提示“Chrome正受到自动测试软件控制” Collections.singletonList("enable-automation")
//options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
//options.setExperimentalOption("useAutomationExtension", false);
//打开cmd 进入到Google Chrome目录下运行如下命令:
//chrome.exe --remote-debugging-port=9222 --user-data-dir="F:\selenum\AutomationProfile"
//options.setExperimentalOption("debuggerAddress","127.0.0.1:9222");
//设置代理
//options.addArguments("--proxy-server=http://127.0.0.1:8080");
//driver = new RemoteWebDriver(url, DesiredCapabilities.chrome());
//不加载图片,加快访问速度 1允许 2禁止
//Map prefs = new HashMap();
//prefs.put("profile.managed_default_content_settings.images", 1);
//options.setExperimentalOption("prefs", prefs);
//使用本地的Google浏览器,一次只能打开一个
//options.addArguments("user-data-dir=C:/Users/Administrator/AppData/Local/Google/Chrome/User Data");
//关闭驱动并退出
public static void doCloseQuit(){
if(driver != null) {
driver.close();
driver.quit();
}
}
driver.findElement(By.id("login_id")).clear(); //获取id是login_id的元素,并清除内容
driver.findElement(By.id("login_id")).sendKeys("xxx"); //获取id是login_id的元素,并输入xxx内容
driver.findElement(By.id("continueBtn")).click(); //获取id是continueBtn的元素,并模拟执行点击事件
.sendKeys(Keys.ENTER); //相当于按键盘上的Enter(回车)
//骚操作By.xpath,任意的去匹配你要获取的元素,下面就是获取id是rptBody元素内的div内的table元素
By by = By.xpath(".//*[@id='rptBody']/div/table");
WebElement tableElement =driver.findElement(by);
这种写法是如果在div内有多个table获取的是第一个table元素
By by = By.xpath(".//*[@id='rptBody']/div/table[1]");
//同级元素
By by = By.xpath(".//input[@id='ids']/../span");
//执行js脚本方法
String jString="Login()";
((JavascriptExecutor)driver).executeScript(jString);
下拉选择框获取选中的值
WebElement selectWebElement = driver.findElement(By.id("_jt_page_size"));
Select select = new Select(selectWebElement);
String s = select.getFirstSelectedOption().getText();
//如果你需要获取 iframe 内的元素需要一下流程才能获取:
//进入到 iframe 内
WebElement iframe =driver.findElement(By.id("iframe"));
driver.switchTo().frame(iframe);
//获取iframe 内元素的操作
...
// 回到主窗口
driver.switchTo().defaultContent();
/**
* 浏览器后台运行,向下滑动
* @param url
* @return
*/
public static DocumentgetDocument(String url){
Document doc =null;
//可使用的浏览器有:IE浏览器(webdriver.ie.driver)
//火狐浏览器 (webdriver.gecko.driver)
//谷歌浏览器 (webdriver.chrome.driver)
// 是使用那个浏览器 chromedriver所在的位置
System.setProperty("webdriver.chrome.driver", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe");
// InternetExplorerDriver() 浏览器
// FirefoxDriver() 火狐浏览器
//谷歌浏览器
WebDriver driver =null;
//创建chrome参数对象
ChromeOptions options =new ChromeOptions();
//浏览器后台运行
options.addArguments("headless");
driver =new ChromeDriver(options);
driver.get(url);
//等待几秒
try {
//向下滚动 方法一
//JavascriptExecutor js = (JavascriptExecutor)driver;
//js.executeScript("scrollTo(0,20000)");
//向下滚动 方法二
((JavascriptExecutor)driver).executeScript("scrollTo(0,10000)");
Thread.sleep(20000);
}catch (InterruptedException e) {
e.printStackTrace();
}
doc = Jsoup.parse(driver.getPageSource());
//关闭浏览器
driver.close();
driver.quit();
return doc;
}