参考官网链接:https://www.selenium.dev/documentation/webdriver/locating_elements/
chrome驱动连接:http://chromedriver.storage.googleapis.com/index.html
首先要明确:
我们的页面中有些dom是在页面加载完成后(document.readyState后)就出现的,而有些dom元素,是通过js动态生成加入的。例如document.body.appendChild(newElement),或是因为触发了某些鼠标或键盘事件,而动态生成或显示的(display:block;)。例如常见的点击或touch触发了modal模态框,popper气泡框,下拉列表等。或者服务端接口暂时没有返回数据,渲染内容为空等异步情况。所以我们可以说
dom是存在异步的
。而selenium的操作是同步的
,所以需要协调两者
。所以有了wait方法和sleep方法。
配置chrome驱动:
Windows下,直接把chromedriver.exe文件放入自己项目的根目录下即可,selenium会找到它
linux下,把chromedriver设置为可执行chmod +x chromedriver,然后把它软连接为 /usr/local/bin/chromedriver中,selenium就能找到这个驱动了
在selenium中:
WebDriver 代表浏览器
WebElement 表示特定的 DOM 节点(控件,例如链接或输入字段等)
所有方法基本上都是返回promise,所以要配合使用async/await,按顺序执行流程
对象的几种类型:
- Locator类型 代表一个定位器,类似于css选择器,但功能更强大
- WebDriver类型 代表浏览器
- WebElement类型 代表一个dom元素
- WebElementPromise类型 代表一个会返回WebElement的promise
- Condition类型 代表wait方法的第一个入参
- WebElementCondition类型 返回的WebElement将作为wait方法的判定条件或返回值
- function(){ return xxx } 返回的任何真值将作为wait方法的判定条件或返回值
wait方法和sleep方法:
WebDriver类型具有wait方法和sleep方法
wait方法主要有四个入参,第一个为Condition类型,第二个为最多等待时间Number类型
wait方法可以没有返回值,如果有返回值的话,它等于第一个参数返回的真值。
在第一个参数没有返回真值期间,wait方法会循环执行,阻塞住主线程,等待条件判定结果,直至超时报错。
until需要在wait方法中使用。
因此我们可以这样获取WebElement:
// 轮询获取target,最多等待10秒
let target = await driver.wait(
until.elementLocated(By.css("#title")),
10000
);
// 不要直接采取这种方式,可能会获取不到异步的dom
let target = await driver.findElement(By.css("#title"));
sleep方法,只有一个入参,代表着需要主线程阻塞多久。这个一般用于我们触发了一个按钮,然后弹框出现。这时需要我们在触发完按钮之后“等一会”,等弹框中的内容加载完毕,然后我们在继续流程,防止某些元素没找到,或者不可交互。
没找到:是指页面上根本没有这个dom
不可交互:是指这个dom元素不可见,比如hidden或none
// 3秒后操作填报modal框
...
await modalbutton.click();
await driver.sleep(3000);
...
executeScript方法:
它可以执行javascript语句,可以类似成eval()。它的第二个参数可以是一个WebElement,也就是说我们可以对某个已获取到的WebElement执行js,类似于操纵此dom。使用时以arguments代表WebElement或WebElements。
// 获取WebElement
const box = await driver.wait(
until.elementLocated(By.css("#box")),
10000
);
// 获取WebElement的offsetTop属性
const offsetTop = await driver.executeScript(
"return arguments[0].offsetTop",
box
);
设置cookies:
需要先加载页面,才能设置cookies。
比如我们get的网址是一个需要登陆态的网址,那么我们需要先get这个网址,然后添加这个网址登陆所需的cookies,然后再get一遍这个网址。三步完成设置cookie登陆。
// 只有先访问该页面,才能设置cookie
await driver.get("http://xxx.com/ts/#/manage/work");
// 设置多个所需的cookie
await driver.manage().addCookie(cookie1);
await driver.manage().addCookie(cookie2);
await driver.manage().addCookie(cookie3);
...
// 可以等待一小会
await driver.sleep(1000);
// cookie设置之后,再回到该页面。不要使用await driver.navigate().refresh(),我们需要主动触发跳转动作
await driver.get("http://xxx.com/ts/#/manage/work");
使用chrome的无头模式:
const { Builder } = require("selenium-webdriver");
const chrome = require("selenium-webdriver/chrome");
let opts = new chrome.Options();
(async function () {
const driver = new Builder()
.forBrowser("chrome")
.setChromeOptions(
opts.addArguments([
"--no-sandbox", // 配置不使用沙箱,Linux下需要此配置,允许root用户执行chrome
"--disable-dev-shm-usage",// 配置共享内存相关,防止chrome崩溃
"--headless",// 配置无头模式
])
)
.build();
try {
// 此网站可以检测浏览器特征,反爬
await driver.get("https://bot.sannysoft.com/");
} catch (error) {
console.log(error, "捕获异常");
await driver.quit();
}
})();