0
# Element Finding and Interaction
1
2
This document covers element finding strategies and interaction methods in Python Selenium WebDriver. It includes locator strategies, WebElement methods, and best practices for element interaction.
3
4
## Locator Strategies (By Class)
5
6
The `By` class provides constants for different element locating strategies.
7
8
{ .api }
9
```python
10
from selenium.webdriver.common.by import By
11
12
class By:
13
ID = "id"
14
XPATH = "xpath"
15
LINK_TEXT = "link text"
16
PARTIAL_LINK_TEXT = "partial link text"
17
NAME = "name"
18
TAG_NAME = "tag name"
19
CLASS_NAME = "class name"
20
CSS_SELECTOR = "css selector"
21
```
22
23
**Description**: Set of supported locator strategies for finding elements.
24
25
**Locator Types**:
26
- `ID`: Select element by its ID attribute
27
- `XPATH`: Select element via XPath expression
28
- `LINK_TEXT`: Select link element by exact text content
29
- `PARTIAL_LINK_TEXT`: Select link element by partial text content
30
- `NAME`: Select element by name attribute
31
- `TAG_NAME`: Select element by tag name
32
- `CLASS_NAME`: Select element by class name
33
- `CSS_SELECTOR`: Select element by CSS selector
34
35
**Custom Finders**:
36
37
{ .api }
38
```python
39
@classmethod
40
def register_custom_finder(cls, name: str, strategy: str) -> None
41
```
42
43
**Description**: Register a custom finder strategy.
44
45
**Parameters**:
46
- `name`: Name of the custom finder
47
- `strategy`: Strategy string for the finder
48
49
{ .api }
50
```python
51
@classmethod
52
def get_finder(cls, name: str) -> Optional[str]
53
```
54
55
**Description**: Get a finder strategy by name.
56
57
**Parameters**:
58
- `name`: Name of the finder
59
60
**Returns**: Strategy string or None if not found
61
62
{ .api }
63
```python
64
@classmethod
65
def clear_custom_finders(cls) -> None
66
```
67
68
**Description**: Clear all custom finders.
69
70
## Element Finding Methods
71
72
### Single Element Finding
73
74
{ .api }
75
```python
76
def find_element(self, by: str = By.ID, value: Optional[str] = None) -> WebElement
77
```
78
79
**Description**: Find an element given a By strategy and locator.
80
81
**Parameters**:
82
- `by`: The locating strategy to use (default: By.ID)
83
- `value`: The locator value
84
85
**Returns**: WebElement object
86
87
**Raises**: NoSuchElementException if element is not found
88
89
**Supported locator strategies**:
90
- `By.ID`: Locate by element ID
91
- `By.NAME`: Locate by the `name` attribute
92
- `By.XPATH`: Locate by an XPath expression
93
- `By.CSS_SELECTOR`: Locate by a CSS selector
94
- `By.CLASS_NAME`: Locate by class name
95
- `By.TAG_NAME`: Locate by tag name
96
- `By.LINK_TEXT`: Locate by exact link text
97
- `By.PARTIAL_LINK_TEXT`: Locate by partial link text
98
99
**Examples**:
100
```python
101
from selenium.webdriver.common.by import By
102
103
# Find by ID
104
element = driver.find_element(By.ID, "myElement")
105
106
# Find by XPath
107
element = driver.find_element(By.XPATH, "//div[@class='container']")
108
109
# Find by CSS selector
110
element = driver.find_element(By.CSS_SELECTOR, ".btn.btn-primary")
111
112
# Find by class name
113
element = driver.find_element(By.CLASS_NAME, "header")
114
115
# Find by tag name
116
element = driver.find_element(By.TAG_NAME, "h1")
117
118
# Find by name attribute
119
element = driver.find_element(By.NAME, "username")
120
121
# Find by link text
122
element = driver.find_element(By.LINK_TEXT, "Click Here")
123
124
# Find by partial link text
125
element = driver.find_element(By.PARTIAL_LINK_TEXT, "Click")
126
```
127
128
### Multiple Elements Finding
129
130
{ .api }
131
```python
132
def find_elements(self, by: str = By.ID, value: Optional[str] = None) -> List[WebElement]
133
```
134
135
**Description**: Find elements given a By strategy and locator.
136
137
**Parameters**:
138
- `by`: The locating strategy to use (default: By.ID)
139
- `value`: The locator value
140
141
**Returns**: List of WebElement objects (empty list if no elements found)
142
143
**Examples**:
144
```python
145
# Find all elements with a class
146
elements = driver.find_elements(By.CLASS_NAME, "item")
147
148
# Find all links
149
links = driver.find_elements(By.TAG_NAME, "a")
150
151
# Find all elements matching XPath
152
items = driver.find_elements(By.XPATH, "//div[contains(@class, 'product')]")
153
```
154
155
## WebElement Class
156
157
{ .api }
158
```python
159
from selenium.webdriver.remote.webelement import WebElement
160
161
class WebElement(BaseWebElement):
162
def __init__(self, parent, id_: str) -> None
163
```
164
165
**Description**: Represents a DOM element. Generally, all interesting operations that interact with a document will be performed through this interface.
166
167
**Parameters**:
168
- `parent`: The WebDriver instance that found this element
169
- `id_`: The element ID from the WebDriver protocol
170
171
## WebElement Properties
172
173
{ .api }
174
```python
175
@property
176
def tag_name(self) -> str
177
```
178
179
**Description**: This element's tagName property.
180
181
**Returns**: The tag name of the element
182
183
**Example**:
184
```python
185
element = driver.find_element(By.ID, 'foo')
186
print(element.tag_name) # e.g., "div", "input", "a"
187
```
188
189
{ .api }
190
```python
191
@property
192
def text(self) -> str
193
```
194
195
**Description**: The text of the element.
196
197
**Returns**: The visible text of the element
198
199
**Example**:
200
```python
201
element = driver.find_element(By.ID, 'content')
202
print(element.text) # Visible text content
203
```
204
205
{ .api }
206
```python
207
@property
208
def size(self) -> dict
209
```
210
211
**Description**: The size of the element.
212
213
**Returns**: Dictionary with 'width' and 'height' keys
214
215
**Example**:
216
```python
217
element = driver.find_element(By.ID, 'banner')
218
size = element.size
219
print(f"Width: {size['width']}, Height: {size['height']}")
220
```
221
222
{ .api }
223
```python
224
@property
225
def location(self) -> dict
226
```
227
228
**Description**: The location of the element in the renderable canvas.
229
230
**Returns**: Dictionary with 'x' and 'y' keys
231
232
**Example**:
233
```python
234
element = driver.find_element(By.ID, 'button')
235
location = element.location
236
print(f"X: {location['x']}, Y: {location['y']}")
237
```
238
239
{ .api }
240
```python
241
@property
242
def rect(self) -> dict
243
```
244
245
**Description**: A dictionary with the size and location of the element.
246
247
**Returns**: Dictionary with 'x', 'y', 'width', and 'height' keys
248
249
**Example**:
250
```python
251
element = driver.find_element(By.ID, 'modal')
252
rect = element.rect
253
print(f"Position: ({rect['x']}, {rect['y']})")
254
print(f"Size: {rect['width']} x {rect['height']}")
255
```
256
257
## WebElement Interaction Methods
258
259
### Basic Interaction
260
261
{ .api }
262
```python
263
def click(self) -> None
264
```
265
266
**Description**: Clicks the element.
267
268
**Example**:
269
```python
270
button = driver.find_element(By.ID, 'submit-btn')
271
button.click()
272
```
273
274
{ .api }
275
```python
276
def clear(self) -> None
277
```
278
279
**Description**: Clears the text if it's a text entry element.
280
281
**Example**:
282
```python
283
text_field = driver.find_element(By.NAME, 'username')
284
text_field.clear()
285
```
286
287
{ .api }
288
```python
289
def send_keys(self, *value: str) -> None
290
```
291
292
**Description**: Simulates typing into the element.
293
294
**Parameters**:
295
- `*value`: A string to send, or key combinations using Keys class
296
297
**Example**:
298
```python
299
from selenium.webdriver.common.keys import Keys
300
301
text_field = driver.find_element(By.NAME, 'search')
302
text_field.send_keys('Python Selenium')
303
text_field.send_keys(Keys.ENTER)
304
305
# Clear and type new text
306
text_field.send_keys(Keys.CONTROL + 'a') # Select all
307
text_field.send_keys(Keys.DELETE) # Delete
308
text_field.send_keys('New text')
309
```
310
311
{ .api }
312
```python
313
def submit(self) -> None
314
```
315
316
**Description**: Submits a form. If this element is a form, or an element within a form, this will submit that form.
317
318
**Example**:
319
```python
320
form = driver.find_element(By.TAG_NAME, 'form')
321
form.submit()
322
323
# Or submit via any element within the form
324
input_field = driver.find_element(By.NAME, 'username')
325
input_field.submit()
326
```
327
328
### Element State Methods
329
330
{ .api }
331
```python
332
def is_selected(self) -> bool
333
```
334
335
**Description**: Returns whether the element is selected (for checkboxes, radio buttons, and select options).
336
337
**Returns**: True if element is selected, False otherwise
338
339
**Example**:
340
```python
341
checkbox = driver.find_element(By.ID, 'agree-terms')
342
if checkbox.is_selected():
343
print("Checkbox is checked")
344
else:
345
checkbox.click() # Check the checkbox
346
```
347
348
{ .api }
349
```python
350
def is_enabled(self) -> bool
351
```
352
353
**Description**: Returns whether the element is enabled.
354
355
**Returns**: True if element is enabled, False otherwise
356
357
**Example**:
358
```python
359
submit_btn = driver.find_element(By.ID, 'submit')
360
if submit_btn.is_enabled():
361
submit_btn.click()
362
else:
363
print("Submit button is disabled")
364
```
365
366
{ .api }
367
```python
368
def is_displayed(self) -> bool
369
```
370
371
**Description**: Returns whether the element is visible to a user.
372
373
**Returns**: True if element is displayed, False otherwise
374
375
**Example**:
376
```python
377
modal = driver.find_element(By.ID, 'error-modal')
378
if modal.is_displayed():
379
print("Error modal is visible")
380
close_btn = modal.find_element(By.CLASS_NAME, 'close')
381
close_btn.click()
382
```
383
384
### Attribute and Property Methods
385
386
{ .api }
387
```python
388
def get_attribute(self, name: str) -> Optional[str]
389
```
390
391
**Description**: Gets the given attribute or property of the element.
392
393
**Parameters**:
394
- `name`: Name of the attribute/property to retrieve
395
396
**Returns**: The value of the attribute/property, or None if not set
397
398
**Example**:
399
```python
400
link = driver.find_element(By.TAG_NAME, 'a')
401
href = link.get_attribute('href')
402
class_name = link.get_attribute('class')
403
data_value = link.get_attribute('data-value')
404
```
405
406
{ .api }
407
```python
408
def get_dom_attribute(self, name: str) -> str
409
```
410
411
**Description**: Gets the given attribute of the element from the DOM.
412
413
**Parameters**:
414
- `name`: Name of the attribute to retrieve
415
416
**Returns**: The attribute value
417
418
**Example**:
419
```python
420
element = driver.find_element(By.ID, 'custom-element')
421
custom_attr = element.get_dom_attribute('data-custom')
422
```
423
424
{ .api }
425
```python
426
def get_property(self, name: str) -> Union[str, bool, WebElement, dict]
427
```
428
429
**Description**: Gets the given property of the element.
430
431
**Parameters**:
432
- `name`: Name of the property to retrieve
433
434
**Returns**: The property value
435
436
**Example**:
437
```python
438
input_field = driver.find_element(By.NAME, 'email')
439
value = input_field.get_property('value')
440
checked = checkbox.get_property('checked') # Returns boolean
441
```
442
443
{ .api }
444
```python
445
def value_of_css_property(self, property_name: str) -> str
446
```
447
448
**Description**: The value of a CSS property.
449
450
**Parameters**:
451
- `property_name`: CSS property name
452
453
**Returns**: The value of the CSS property
454
455
**Example**:
456
```python
457
element = driver.find_element(By.ID, 'header')
458
color = element.value_of_css_property('color')
459
background = element.value_of_css_property('background-color')
460
font_size = element.value_of_css_property('font-size')
461
```
462
463
### Screenshot Methods
464
465
{ .api }
466
```python
467
def screenshot_as_base64(self) -> str
468
```
469
470
**Description**: Gets the screenshot of the current element as a base64 encoded string.
471
472
**Returns**: Base64 encoded string of the PNG image
473
474
{ .api }
475
```python
476
def screenshot_as_png(self) -> bytes
477
```
478
479
**Description**: Gets the screenshot of the current element as binary data.
480
481
**Returns**: Binary data of the PNG image
482
483
{ .api }
484
```python
485
def screenshot(self, filename: str) -> bool
486
```
487
488
**Description**: Saves a screenshot of the current element to a PNG image file.
489
490
**Parameters**:
491
- `filename`: The full path to save the screenshot
492
493
**Returns**: True if the screenshot was saved successfully, False otherwise
494
495
**Example**:
496
```python
497
element = driver.find_element(By.ID, 'chart')
498
499
# Save screenshot to file
500
element.screenshot('/path/to/element_screenshot.png')
501
502
# Get as binary data
503
png_data = element.screenshot_as_png()
504
505
# Get as base64 string
506
base64_data = element.screenshot_as_base64()
507
```
508
509
### Accessibility Methods
510
511
{ .api }
512
```python
513
def aria_role(self) -> str
514
```
515
516
**Description**: Gets the ARIA role of the current element.
517
518
**Returns**: The ARIA role attribute value
519
520
{ .api }
521
```python
522
def accessible_name(self) -> str
523
```
524
525
**Description**: Gets the accessible name of the current element.
526
527
**Returns**: The accessible name of the element
528
529
**Example**:
530
```python
531
button = driver.find_element(By.ID, 'submit-btn')
532
role = button.aria_role
533
name = button.accessible_name
534
print(f"Button role: {role}, accessible name: {name}")
535
```
536
537
## Element Finding from Elements
538
539
WebElements also support finding child elements:
540
541
{ .api }
542
```python
543
def find_element(self, by: str = By.ID, value: Optional[str] = None) -> WebElement
544
```
545
546
{ .api }
547
```python
548
def find_elements(self, by: str = By.ID, value: Optional[str] = None) -> List[WebElement]
549
```
550
551
**Example**:
552
```python
553
# Find a container element
554
container = driver.find_element(By.ID, 'products')
555
556
# Find child elements within the container
557
products = container.find_elements(By.CLASS_NAME, 'product-item')
558
559
for product in products:
560
title = product.find_element(By.CLASS_NAME, 'product-title')
561
price = product.find_element(By.CLASS_NAME, 'product-price')
562
print(f"{title.text}: {price.text}")
563
```
564
565
## Shadow DOM Support
566
567
{ .api }
568
```python
569
def shadow_root(self) -> ShadowRoot
570
```
571
572
**Description**: Returns a shadow root of the element if there is one, or an error.
573
574
**Returns**: ShadowRoot object
575
576
**Example**:
577
```python
578
# Find element with shadow DOM
579
host_element = driver.find_element(By.ID, 'shadow-host')
580
581
# Access shadow root
582
shadow_root = host_element.shadow_root
583
584
# Find elements within shadow DOM
585
shadow_element = shadow_root.find_element(By.CSS_SELECTOR, '.shadow-content')
586
```
587
588
## Best Practices for Element Interaction
589
590
### 1. Robust Element Finding
591
592
```python
593
from selenium.common.exceptions import NoSuchElementException, TimeoutException
594
from selenium.webdriver.support.ui import WebDriverWait
595
from selenium.webdriver.support import expected_conditions as EC
596
597
def find_element_safely(driver, by, value, timeout=10):
598
"""Safely find element with timeout"""
599
try:
600
element = WebDriverWait(driver, timeout).until(
601
EC.presence_of_element_located((by, value))
602
)
603
return element
604
except TimeoutException:
605
print(f"Element not found: {by}={value}")
606
return None
607
608
# Usage
609
element = find_element_safely(driver, By.ID, 'submit-btn')
610
if element:
611
element.click()
612
```
613
614
### 2. Waiting for Element State
615
616
```python
617
from selenium.webdriver.support import expected_conditions as EC
618
619
# Wait for element to be clickable
620
wait = WebDriverWait(driver, 10)
621
button = wait.until(EC.element_to_be_clickable((By.ID, 'submit-btn')))
622
button.click()
623
624
# Wait for element to be visible
625
element = wait.until(EC.visibility_of_element_located((By.ID, 'result')))
626
print(element.text)
627
```
628
629
### 3. Handling Dynamic Content
630
631
```python
632
def wait_for_text_change(element, old_text, timeout=10):
633
"""Wait for element text to change"""
634
wait = WebDriverWait(driver, timeout)
635
wait.until(lambda d: element.text != old_text)
636
637
# Usage
638
status_element = driver.find_element(By.ID, 'status')
639
old_status = status_element.text
640
# Trigger some action
641
submit_button.click()
642
# Wait for status to update
643
wait_for_text_change(status_element, old_status)
644
```
645
646
### 4. Efficient Element Interaction
647
648
```python
649
def interact_with_form(driver):
650
"""Efficient form interaction pattern"""
651
# Find form container once
652
form = driver.find_element(By.ID, 'user-form')
653
654
# Find all inputs within the form
655
username = form.find_element(By.NAME, 'username')
656
password = form.find_element(By.NAME, 'password')
657
submit_btn = form.find_element(By.TYPE, 'submit')
658
659
# Perform interactions
660
username.clear()
661
username.send_keys('testuser')
662
663
password.clear()
664
password.send_keys('password123')
665
666
# Submit form
667
submit_btn.click()
668
```
669
670
### 5. Error Handling
671
672
```python
673
from selenium.common.exceptions import (
674
NoSuchElementException,
675
ElementNotInteractableException,
676
StaleElementReferenceException
677
)
678
679
def safe_click(element, retries=3):
680
"""Safely click element with retry logic"""
681
for attempt in range(retries):
682
try:
683
element.click()
684
return True
685
except StaleElementReferenceException:
686
# Re-find the element
687
element = driver.find_element(By.ID, element.id)
688
except ElementNotInteractableException:
689
# Wait a bit and try again
690
time.sleep(0.5)
691
return False
692
```