javascript的异步-Python+Selenium 如何使用execute_async_script

2023-08-23 0 8,083 百度已收录

Selenium 如何使用execute_async_script 的回调 前言

我在百度的时候,好像关于execute_script的解释很多,但是关于execute_async_script的解释却不多。 我也听到一些文章问为什么callback不能用(用python写的时候一定不能用……)所以我也写了一篇关于execute_async_script的用法的文章。

根据

很多使用错误是由于对概念、模型等问题的理解错误造成的。 这里首先要讨论一下Python和JS的一些基本概念或者相关理论。 否则,仅仅靠代码可能永远无法理解问题的本质。

如果你已经了解很多JS的异步机制(比如Promise等)javascript的异步,可以跳过基础部分

如果您只是不想阅读这些废话,您可以直接跳到完整的示例和其他几个示例。 我相信聪明的你一看就明白了。

1.JS异步

JS是一种单线程语言,是为浏览器设计的。 JS 本身不支持任何延迟、冻结或线程锁定操作(没有人希望在上网时被卡住,对吧?)javascript的异步,而是使用 Callback 技术来完成延迟或耗时的任务。

比如你想在JS中调用funcA,1秒后再调用funcB,就必须这样写:

funcA()
setTimeout(funcB, 1000)

仔细观察funcA旁边有括号,funcB前面没有括号。 这意味着funcB作为参数传递给setTimeout函数,也就是说1s后通知主线程调用funcB。

这行代码并不会导致线程冻结,只是将funcB添加到JS任务队列中等待执行。 如果前面有代码,则立即执行后面的代码。 例如下面的代码,执行顺序是A -> C -> B。

funcA()
setTimeout(funcB, 1000)
funcC()

更具体的内容可以查看百度相关主题关于js线程、js异步、js Promise、js异步编程等内容。 这里,你只需要对JS异步编程思想做一些了解即可。

2.Python同步

Python是多线程语言,没有复杂的反弹机制。 如果使用计时,当前线程将被“锁定”,直到该行结束。

funcA()
time.sleep(1)
funcB()

例如,前面的代码将按照 A -> B 的顺序。A 和 B 之间的时间为一秒。 当程序执行到time.sleep时,线程会等待,不会执行其他代码。

这和JS的异步有很大不同。 刚才A -> C -> B的情况,JS主线程的执行时间可能只有几微秒(A和C的执行是瞬时的,B的执行也是瞬时的),而中间1000毫秒没有执行任何代码。

3. 硒

Selenium是一个测试框架,主要语言是Python,那么同步和异步哪个更简单呢? 显然,Python的同步写法简单,符合人类思维。

其实execute_async_script也是这样设计的。 它被设计用来执行异步代码,但是你不可能在Python上编写异步代码来解决这个问题。

所以其实这个函数就是一个同步函数。 当程序执行到execute_async_script时,仍然会等待代码完成,然后继续执行下一行。

例如:

javascript的异步-Python+Selenium 如何使用execute_async_script

funcA()
result = browser.execute_async_script('// some script')
funcB()

此类代码会先执行funcA,然后线程会卡在execute_async_script,等待execute_async_script执行完毕,再执行funcB。 这里的结果是代码执行的结果。 定义方法非常简单。 如果熟悉JS的Promise机制会更容易理解。

4. 异步和反弹

显然,我们可以这么简单的理解,你给selenium一段代码,selenium会把这段代码交给chrome去执行,然后等待执行完成,selenium会把结果返回给你(return到蟒蛇)。

但是,JS异步编程存在一个问题。 虽然执行了异步代码,但没有返回结果。 这是异步编程的一个主要特征。 (不明白的可以回头看一下JS异步部分)

那么你可能要问了,代码已经执行完毕,还没有计算结果,那么如何获取执行结果呢?

答案是:回调

假设我现在有一个异步流程,需要预估很长时间,而这个预估是在其他线程中完成的,那么我封装这个流程之后,别人怎么能收到这个结果呢? 。

在JS中,只要提前给出弹跳就可以实现这个功能。

下面是一个假设的例子,请仔细观察主叫方和被叫方的区别,仔细理解:

// 主要代码部分,执行计算,然后拿到结果
someComplicatedCalculation(1, 1, function (result) {
    console.log(result)
})
// 给定参数,异步计算,并拿到结果
function someComplicatedCalculation(a, b, callback) {
    const result = a + b // 一段很复杂的计算过程
    // 调用callback函数,传入参数是计算结果
    callback(result)
}

我们先看一下someComplicatedCalculation的用法。 输入a和b是计算参数,即两个加数,但结果不是这个函数的返回值,或者这个函数没有返回值。 那么结果在哪里呢?

这个函数的第三个参数是画龙点睛的作用。 您需要传入一个函数。 该函数的第一个参数是估计的结果。

然后,您只需将所有估计的代码复制并粘贴到该函数中,就可以得到估计的结果。 (当然,这也会产生问题,有兴趣的可以用百度js回调地狱)

也就是说,第三个参数是一个函数,需要传入一个函数作为参数。

接下来我们看看someComplicatedCalculation是如何实现的? 重点是callback(result),也就是说只要在这个参数前面加上括号,这个函数就会被调用。

显然,负责编译估计过程的人(被调用者)并不知道调用该函数的人(调用者)之后会做什么,所以他只是将结果扔到函数上,而他之后想做的就是由他决定。 这取决于调用该函数的人(调用者决定如何使用估计结果)。

5. 硒

我们回到Selenium,与第四个问题类似,这里,selenium是调用者,而你想让浏览器执行的代码是被调用者,所以你应该执行一个叫做callback的函数,把你的估计结果传递到这个函数,这样selenium就可以得到你给出的结果。 而当收到结果时,selenium 就知道异步进程已经执行完毕,无需再等待。

所以,正确的写法,回调自然是在被调用者中调用,也就是在JS中调用。 (这就是为什么recall肯定不是写在python上的)

例如:

result = browser.execute_async_script(js_script)

// js_script的内容
setTimeout(function () {
  callback('这是我的计算结果')
}, 1000)

这样,python主线程就会停在execute_async_script行,等待一秒左右,最后收到js的执行结果,最终的结果就是字符串“This is my approximation result”。

javascript的异步-Python+Selenium 如何使用execute_async_script

Selenium中execute_async_script的使用1.如何在JS中执行callback

最后还剩下一个问题,js中的回调在哪里呢?

这需要在原始文档中进行解释......但我很幸运能够听到它。

这是参考链接

此回调始终作为最后一个参数注入到执行的函数中。

这和Selenium的工作原理有关。 最后一个参数的获取方式如下:

const callback = arguments[arguments.length - 1]

修饰符 const 和 var 并不重要。 Arguments不是变量,而是关键字,代表当前函数栈的所有参数,是类似字段的结果。 总之,通过这种方式就可以得到回调。

2. 完整样品

// python代码
from selenium import webdriver
import time
# 读取JS代码,这里保存在test.js文件中
def get_script():
    with open('./test.js', encoding='utf-8') as f:
        js_script = f.read()
        return js_script
# 主函数
def main():
	# 启动chrome,这都是selenium标准用法,不清楚请百度
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    browser = webdriver.Chrome(options=chrome_options, executable_path='chromedriver.exe')
    mainUrl = 'http://www.baidu.com'
    browser.get(mainUrl)
	# 异步执行JS代码并获取结果,同时记录前后时间
    start_time = time.time()
    result = browser.execute_async_script(get_script())
    end_time = time.time()
	# 打印结果,并显示结果的类型
	print('执行结果:', result)
    print('结果类型:', type(result))
	# 打印开始和结束时间,以及总时长
    print('运行时长:', end_time - start_time)
    browser.quit()
if __name__ == '__main__':
    main()

// test.js的内容
const callback = arguments[arguments.length - 1]
setTimeout(function() {
    callback('Hello world!')
}, 1000)

运算结果

javascript的异步-Python+Selenium 如何使用execute_async_script

DevTools listening on ws://127.0.0.1:57796/devtools/browser/69eeec93-a5a8-48e1-a143-cc0aeea73600
执行结果: Hello world!
结果类型: 
运行时长: 1.0462801456451416

可以看到程序成功获取到了JS中的执行结果,而Python的主线程也等待了1秒左右,即还在等待程序执行结束。

3. 返回字段实例

Python代码保持不变

// test.js的内容
const callback = arguments[arguments.length - 1]
setTimeout(function() {
    callback([1, 2, 3])
}, 1000)

运算结果

DevTools listening on ws://127.0.0.1:57870/devtools/browser/cc3543c7-c8ca-4ae7-85a5-61bebb13684a
执行结果: [1, 2, 3]
结果类型: 
运行时长: 1.0500686168670654

3.返回对象的实例

Python代码保持不变

// test.js的内容
const callback = arguments[arguments.length - 1]
setTimeout(function() {
    callback({
        id: 12,
        book_name: '颈椎病康复指南',
        author: 'CSDN'
    })
}, 1000)

运算结果

DevTools listening on ws://127.0.0.1:57959/devtools/browser/3ad1d611-66cb-40f2-ad2b-1fa27dab822c
执行结果: {'author': 'CSDN', 'book_name': '颈椎病康复指南', 'id': 12}
结果类型: 
运行时长: 1.0560016632080078

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 javascript javascript的异步-Python+Selenium 如何使用execute_async_script https://www.wkzy.net/game/142552.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务