selenium is low-level tool, so can be complex to use. This vignette gives an overview of the important functions of selenium, and how to use them.
First, let’s create a new session (assuming that you have a server running):
session <- SeleniumSession$new()
First, navigate to the website you want to automate with
SeleniumSession$navigate()
:
session$navigate("http://www.tidyverse.org")
Navigation
Use SeleniumSession$back()
and
SeleniumSession$forward()
to navigate back and forward in
the navigation history, and SeleniumSession$refresh()
to
reload the current page
session$back()
session$forward()
session$refresh()
session$current_url()
#> [1] "https://www.tidyverse.org/"
Elements
To interact with a webpage, you first need to find the elements you
want to interact with. You can do this using
SeleniumSession$find_element()
and
SeleniumSession$find_elements()
. Both functions take two
arguments: using
and value
. using
specifies the method you want to use to find the element, while
value
is the string you want to search for.
By default, CSS selectors are used
(value = "css selector"
), as they provide a simple and
concise way to find elements:
- Use
"name"
to select an element with the tag namename
. (e.g.div
). - Use
"#id"
to select an element with the idid
. - Use
".class"
to select an element with the classclass
. - Use square brackets to select elements using other properties. For
example,
"input[type='text']"
selects a text input element.
For more information about using CSS selectors, see: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors/Selectors_and_combinators.
Another notable way to select elements is using XPaths. XPaths can be
slightly more verbose than CSS selectors, but are more powerful. Use
using = "xpath"
to use XPaths.
- Use
//tagname
to select an element with the tag nametagname
. - Use
//tagname[@attribute='value']
to select an element with the tag nametagname
and the attributeattribute
with the valuevalue
. - Use
//tagname/childtagname
(single slash) to select an element that is a direct child of thetagname
element. Similarly,/tagname
can be used to select an element that is at the top level of the DOM. - Use
//tagname//childtagname
to select an element that is a child of thetagname
element, but does not have to be directly below it in the DOM.
To learn more about how to use XPaths, see: https://www.w3schools.com/xml/xpath_intro.asp
The other values that using
can take are fairly
self-explanatory (e.g. "tag name"
) will match elements with
the tag name given by value
.
Once you have an element, you can locate further sub-elements using
WebElement$find_element()
and
WebElement$find_elements()
, which will now select from the
element’s children. This is especially useful when a website does not
make much use of classes and ids to label its elements uniquely.
For example, the following code will find all the hex images on the Tidyverse home page:
hex_stickers <- session$
find_element(using = "css selector", value = ".hexBadges")$
find_elements(using = "css selector", value = "img")
Element properties
Once you have an element, there are many properties that you can request from it.
element <- hex_stickers[[1]]
Use WebElement$get_tag_name()
to get the tag name of an
element:
element$get_tag_name()
#> [1] "img"
Use WebElement$get_text()
to get the text inside of an
element:
element$get_text()
#> [1] ""
WebElement$get_attribute()
and
WebElement$get_property()
will return the value or property
of an element (see the documentation for the difference between the
two).
element$get_attribute("src")
#> [1] "/css/images/hex/dplyr.png"
element$get_property("src")
#> [1] "https://www.tidyverse.org/css/images/hex/dplyr.png"
WebElement$get_css_value()
will return the computed CSS
property of an element:
element$get_css_value("background-color")
#> [1] "rgba(0, 0, 0, 0)"
Use WebElement$get_rect()
to get the coordinates and
size of an element:
element$get_rect()
#> $x
#> [1] 192
#>
#> $y
#> [1] 197.5
#>
#> $width
#> [1] 120
#>
#> $height
#> [1] 139
Use WebElement$is_selected()
,
WebElement$is_enabled()
and
WebElement$is_displayed()
to check if an element is
currently selected, enabled or visible.
element$is_selected()
#> [1] FALSE
element$is_enabled()
#> [1] TRUE
element$is_displayed()
#> [1] TRUE
Interacting with an element
There are many different ways to interact with an element.
Use WebElement$click()
to click on an element:
element$click()
Use WebElement$send_keys()
to send text to an input
element:
input <- session$find_element(using = "css selector", value = "input[type='search']")
input$send_keys("filter")
You can use the keys
object to send more advanced key
combinations to an element.
For example, the below code selects all the text inside the element
(<Ctrl-A>
), and then deletes it.
input$send_keys(keys$control, "a", keys$backspace)
However, generally, if you want to clear an input element, use
WebElement$clear()
.
input$clear()
Custom JavaScript
Use SeleniumSession$execute_script()
to execute custom
JavaScript. Any extra arguments will be passed into the script through
the arguments
array, and items can be returned explicitly
using return
. WebElements
can also be passed
in and returned.
session$execute_script("return arguments[0] + arguments[1];", 2, 2)
#> [1] 4
session$execute_script("return arguments[0].parentElement;", input)
#> <WebElement>
#> Public:
#> clear: function (timeout = 20)
#> click: function (timeout = 20)
#> clone: function (deep = FALSE)
#> computed_label: function (timeout = 20)
#> computed_role: function (timeout = 20)
#> find_element: function (using = c("css selector", "xpath", "tag name", "link text",
#> find_elements: function (using = c("css selector", "xpath", "tag name", "link text",
#> get_attribute: function (name, request_body = NULL, timeout = 20)
#> get_css_value: function (name, request_body = NULL, timeout = 20)
#> get_property: function (name, request_body = NULL, timeout = 20)
#> get_rect: function (timeout = 20)
#> get_tag_name: function (timeout = 20)
#> get_text: function (timeout = 20)
#> id: 5dac8efb-433c-4938-bd77-4e3b7e16e708
#> initialize: function (session_id, req, verbose, id)
#> is_displayed: function (timeout = 20)
#> is_enabled: function (timeout = 20)
#> is_selected: function (timeout = 20)
#> screenshot: function (timeout = 20)
#> send_keys: function (..., request_body = NULL, timeout = 20)
#> shadow_root: function (timeout = 20)
#> toJSON: function ()
#> Private:
#> req: httr2_request
#> session_id: a4a24afb-9198-44c9-80b4-f5cff3c2c754
#> verbose: FALSE
SeleniumSession$execute_async_script()
is provided for
when you need to interact with an asynchronous JavaScript API, but is
much less commonly used.
Windows and Tabs
A SeleniumSession
object is not limited to a single
window/tab. Use SeleniumSession$new_window()
to create a
new window or tab, using the type
argument to choose
between the two:
tab <- session$new_window(type = "tab")
window <- session$new_window(type = "window")
tab
#> $handle
#> [1] "a3163e65-a8c4-4975-a5dd-df1d8667008a"
#>
#> $type
#> [1] "tab"
window
#> $handle
#> [1] "ffae140b-bb7d-4007-93f7-63538b18542f"
#>
#> $type
#> [1] "window"
Each window/tab has its own handle: a string that uniquely identifies
it. Use SeleniumSession$window_handle()
to get the handle
of the current window, and SeleniumSession$window_handles()
to get the handle of every open window/tab.
current_handle <- session$window_handle()
current_handle
#> [1] "b4fdb453-039e-4751-9705-f4990435d2a7"
session$window_handles()
#> [[1]]
#> [1] "b4fdb453-039e-4751-9705-f4990435d2a7"
#>
#> [[2]]
#> [1] "a3163e65-a8c4-4975-a5dd-df1d8667008a"
#>
#> [[3]]
#> [1] "ffae140b-bb7d-4007-93f7-63538b18542f"
When a new window/tab is created, it is not automatically switched
to. Use SeleniumSession$switch_to_window()
to switch to a
window/tab with a specific handle:
session$switch_to_window(window$handle)
Use SeleniumSession$close_window()
to close a
window/tab:
session$close_window()
#> [[1]]
#> [1] "b4fdb453-039e-4751-9705-f4990435d2a7"
#>
#> [[2]]
#> [1] "a3163e65-a8c4-4975-a5dd-df1d8667008a"
# Switch to an open window
session$switch_to_window(current_handle)
iframes and the Shadow DOM
There are many methods that web developers use to embed self-contained HTML documents or elements into a page.
One of these is an iframe element, allowing a nested browsing context
to be embedded into a page. For example, iframes are often used to embed
video players into a site. Use
SeleniumSession$switch_to_frame()
to switch to an frame and
select elements within it. You can pass in the index of the frame, or
the iframe
element itself.
session$navigate("https://www.youtube.com")
iframe <- session$find_element(using = "css selector", value = "iframe")
session$switch_to_frame(iframe)
Use SeleniumSession$switch_to_parent_frame()
to switch
to the parent frame of the current one, or use
SeleniumSession$switch_to_frame()
with no arguments to
switch to the top-level browsing context:
session$switch_to_parent_frame()
The Shadow DOM is another way for websites to embed content into a
page, this time into any element. If an element is a shadow root, use
WebElement$shadow_root()
to get the corresponding
ShadowRoot
object. You can then find sub-elements within
the shadow root using ShadowRoot$find_element()
and
ShadowRoot$find_elements()
.