测试人社区

selenium执行JS--JS怎么实现sleep的强制等待?

目的:使用selenium执行js修改12306官网的出发日期,修改为2020-12-30,并打印出来

代码块1这段是正确的代码。第一个sleep是必须要加的,否则日期不会被修改。为了不使用sleep,我上网查找了JS的强行等待的方法setTimeout,于是写了代码块2。但是代码块2的执行结果并不正确,页面中的日期没有变成预期结果,打印结果也没有变成预期结果。

问题:代码块2如何修改才能使结果正确?

代码块1—正确的代码

from time import sleep
from selenium import webdriver
class TestExecuteScript:
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(3)
    def teardown(self):
        self.driver.quit()
    def test_execute_script(self):
        self.driver.get("https://www.12306.cn/index/")
        self.driver.execute_script("a=document.getElementById('train_date');a.removeAttribute('readonly')")
        sleep(2)
        self.driver.execute_script("document.getElementById('train_date').value='2020-12-30'")
        sleep(2)
        print(self.driver.execute_script("return document.getElementById('train_date').value"))

代码块2----修改为JS的setTimeout的不能正确执行的代码

from time import sleep
from selenium import webdriver
class TestExecuteScript:
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(3)
    def teardown(self):
        self.driver.quit()
    def test_execute_script(self):
        self.driver.get("https://www.12306.cn/index/")
        self.driver.execute_script("a=document.getElementById('train_date');a.removeAttribute('readonly')")
        # sleep(2)
        self.driver.execute_script("setTimeout(document.getElementById('train_date').value='2020-12-30',3000)")
        sleep(2)
        print(self.driver.execute_script("return document.getElementById('train_date').value"))

为什么要用js的强制等待。用time.sleep足够了啊

理论上这个js语法是OK的,但尝试了确实等待不了,可能selenium执行JavaScript不支持内部嵌套导致的,有时间我再研究一下;如果是要强等的话,AD老师的回复那样就好,你在js强等与在外面的time.sleep()效果是一致的

查了一下,setTimeout要传入的第一个参数应该是一个函数的引用,而不是函数的执行,所以你直接写了执行语句到那一句的时候会直接执行而不会等待,例如:

setTimeout(alert('aaaa'),1000)
# 这句在控制台执行的话,就会直接弹出alert 而不是等待一秒后弹出

setTimeout(function (){alert('aaaa')},1000)
# 而这句在控制台就会等待一秒后弹出,因为用了一个匿名函数定义来包裹,所以setTimeOut获得的参数是函数的引用,这样就能在等待时间后进行执行了 

所以你的语句改为

        self.driver.execute_script("setTimeout(function (){document.getElementById('train_date').value='2020-12-30'},3000)")

就能够正常的执行了
另外还有一点,因为js的等待是不会影响selenium的执行的,所以这个语句后面的sleep要3秒+ 不然的话上一句还没执行,你的获取信息的js就跑完了肯定拿不到对的值

谢谢老师们的解答,非常棒 :+1: