I think, this question concerns the internal workings of Selenium. In another post Referer missing in HTTP header of Selenium request it becomes apparent that there is a difference between running
driver.execute_script("window.location.href = '{}';".format(url))
and
driver.get("javascript: window.location.href = '{}'".format(url))
The latter command will send Referer
header with the request, the former will not.
Doesn't matter at this point if this is desired behavior or a bug and Referer
should be sent by both commands. Also, window.location.href = ...
is only an example.
Yet, obviously, there must be a difference between running JavaScript with command driver.execute_script("...")
and driver.get("javascript: ..."
if they don't produce the same result. So the question is more about the fact that both commands don't invoke the same Selenium code internally.
What is the difference between both commands?
The answer to your question depends on the browser your driver is running. Selenium itself does not implement these functionalities - it merely invokes the underlying driver's API.
Take a look at the source of WebDriver.execute_script
and WebDriver.get
- they both just call self.execute
, which performs a request to the webdriver.
Chrome, for example, does not support 'javascript:' urls with WebDriver.get
since 2013, as can bee seen in chromium's webdriver implementation.
The actual difference between directly running a JS script and navigating to a 'javascript URL' is embedded deep in each browser's implementation, and might be not very straightforward. A possible reason for the difference you mentioned could be an implementation detail - maybe the browser (that was used when the results you mentioned were produced) only sends a Referer
header when it is in the context of a high level navigation command (driver.get
), and therefore did not include one on a plain javascript-triggered navigation.
TL;DR: I was curious about this and was starting an answer. Then went out of town.
I'm not trying to poach points or anything from @Ni. As he points out, get
and execute_script
call self.execute
, which--in turn--calls a method from the Command
class. For example, Command.GET
or Command.EXECUTE_SCRIPT
. And that's where the trail went cold for me...
the source code
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})
and
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']
which points to
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
"""
and
https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/remote/remote_connection.py#L142 shows a private method called self._commands
, which is a dictionary containing commands that mirror the syntax seen in ..remote/webdriver.py
For example: Command.GET: ('POST', '/session/$sessionId/url')
vs. self.execute(Command.GET, {'url': url})
The endpoints in self._commands
correspond to the https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference, so this is the service "used to marshal commands" (?) or part of it...
(ruby equiv: https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/remote/commands.rb)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With