`driver.execute_script("...")` 和 `driver.get("javascript: ..."` 与 geckodriver/Firefox 有什么区别?

What's the difference between `driver.execute_script("...")` and `driver.get("javascript: ..."` with geckodriver/Firefox?

我认为,这个问题涉及Selenium 的内部工作原理。在另一个 post 中,很明显 运行

之间存在差异
driver.execute_script("window.location.href = '{}';".format(url))

driver.get("javascript: window.location.href = '{}'".format(url))

后面的命令会在请求中发送Referer头,前者不会。

在这一点上,这是期望的行为还是错误并不重要,Referer 应该由两个命令发送。另外,window.location.href = ... 只是一个例子。

然而,显然,运行 JavaScript 与命令 driver.execute_script("...")driver.get("javascript: ..." 之间肯定存在差异,如果它们不产生相同的结果。所以问题更多的是关于这两个命令不会在内部调用相同的 Selenium 代码这一事实。

这两个命令有什么区别?

TL;DR:我对此很好奇并开始回答。然后出城了。

我不是想从@Ni 那里挖点数或任何东西。正如他指出的那样,getexecute_script 调用 self.execute,后者又调用 Command class 中的方法。例如,Command.GETCommand.EXECUTE_SCRIPT。这就是这条路对我来说很冷的地方......


源代码

https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/remote/webdriver.py

def get(self, url):
    """
    Loads a web page in the current browser session.
    """
    self.execute(Command.GET, {'url': url})

def execute_script(self, script, *args):
    """
    Synchronously Executes JavaScript in the current window/frame.

    :Args:
     - script: The JavaScript to execute.
     - \*args: Any applicable arguments for your JavaScript.

    :Usage:
        driver.execute_script('return document.title;')
    """
    converted_args = list(args)
    command = None
    if self.w3c:
        command = Command.W3C_EXECUTE_SCRIPT
    else:
        command = Command.EXECUTE_SCRIPT

    return self.execute(command, {
        'script': script,
        'args': converted_args})['value']

指向

https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/remote/command.py

class Command(object):
    """
    Defines constants for the standard WebDriver commands.
    While these constants have no meaning in and of themselves, they are
    used to marshal commands through a service that implements WebDriver's
    remote wire protocol:
        https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
    """

https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/remote/remote_connection.py#L142 显示了一个名为 self._commands 的私有方法,它是一个字典,其中包含的命令反映了 ..remote/webdriver.py

中的语法

例如:Command.GET: ('POST', '/session/$sessionId/url')self.execute(Command.GET, {'url': url})

self._commands中的端点对应于https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference,所以这是服务"used to marshal commands"(?)或其一部分...

(ruby 等价于: https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/remote/commands.rb)

您问题的答案取决于浏览器,您的 driver 是 运行。 Selenium 本身不实现这些功能 - 它仅调用底层 driver 的 API.

查看 WebDriver.execute_script and WebDriver.get 的来源 - 他们都只是调用 self.execute,它执行对网络的请求driver。

例如,

Chrome 不支持带有 WebDriver.get 的 'javascript:' url,因为 2013, as can bee seen in chromium's webdriver implementation.

直接 运行 JS 脚本和导航到 'javascript URL' 之间的实际区别深植于每个浏览器的实现中,并且可能不是很简单。您提到的差异的一个可能原因可能是实现细节 - 也许浏览器(在生成您提到的结果时使用)仅在 Referer header 的上下文中发送高级导航命令 (driver.get),因此没有包含在普通 javascript-triggered 导航中。