Selenium webdriver: How do I find ALL of an element's attributes?
Asked Answered
F

4

83

In the Python Selenium module, once I have a WebElement object I can get the value of any of its attributes with get_attribute():

foo = elem.get_attribute('href')

If the attribute named 'href' doesn't exist, None is returned.

My question is, how can I get a list of all of the attributes that an element has? There doesn't seem to be a get_attributes() or get_attribute_names() method.

I'm using version 2.44.0 of the Selenium module for Python.

Fillister answered 5/12, 2014 at 1:5 Comment(0)
S
86

It is not possible using a selenium webdriver API, but you can execute a javascript code to get all attributes:

driver.execute_script('var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;', element)

Demo:

>>> from selenium import webdriver
>>> from pprint import pprint
>>> driver = webdriver.Firefox()
>>> driver.get('https://stackoverflow.com')
>>> 
>>> element = driver.find_element_by_xpath('//div[@class="network-items"]/a')
>>> attrs = driver.execute_script('var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;', element)
>>> pprint(attrs)
{u'class': u'topbar-icon icon-site-switcher yes-hover js-site-switcher-button js-gps-track',
 u'data-gps-track': u'site_switcher.show',
 u'href': u'//stackexchange.com',
 u'title': u'A list of all 132 Stack Exchange sites'}

For completeness sake, an alternative solution would be to get the tag's outerHTML and parse the attributes using an HTML parser. Example (using BeautifulSoup):

>>> from bs4 import BeautifulSoup
>>> html = element.get_attribute('outerHTML')
>>> attrs = BeautifulSoup(html, 'html.parser').a.attrs
>>> pprint(attrs)
{u'class': [u'topbar-icon',
            u'icon-site-switcher',
            u'yes-hover',
            u'js-site-switcher-button',
            u'js-gps-track'],
 u'data-gps-track': u'site_switcher.show',
 u'href': u'//stackexchange.com',
 u'title': u'A list of all 132 Stack Exchange sites'}
Scrooge answered 5/12, 2014 at 1:16 Comment(5)
Any idea why this wasn't included in the W3C spec? Seems short-sighted to leave this out w3.org/TR/webdriver/#get-element-attributeSato
@Sato not sure, may it's just that it's not widely use. Far more often a user would want to get a single attribute..good question though, thanks.Scrooge
Alternative: lxml element.attrib returns a nice useable dictionary with all attributes.Foreworn
Tag outerHTML was very useful to be able to pass to BeautifulSoup :)Ola
can you write any script you want or is execute_script limited in some way?Buckels
G
31

The following gets a list of all attributes and their (sometimes translated to strings) values for me, using the PhantomJS or Chrome driver at least:

elem.get_property('attributes')[0]

To just get the names:

x.get_property('attributes')[0].keys()
Grados answered 21/6, 2017 at 1:44 Comment(2)
I found out that there is not a number 0 but string: elem.get_property('attributes')['0']Shall
This is the correct answer, and should be marked so.Mansized
F
16

You can find using element.get_property() method.

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.ultimateqa.com/complicated-page/")

logo = driver.find_element(By.XPATH, "//img[@id='logo']")
attrs=[]
for attr in logo.get_property('attributes'):
    attrs.append([attr['name'], attr['value']])
print(attrs)

Output:

[['src', 'https://www.ultimateqa.com/wp-content/uploads/2019/01/horizontal_on_transparent_by_logaster-2.png'], ['alt', 'Ultimate QA'], ['id', 'logo'], ['data-height-percentage', '100'], ['data-actual-width', '912'], ['data-actual-height', '410']]
Foresee answered 30/5, 2019 at 18:47 Comment(1)
This seems like the right answer, however I am experiencing JavascriptException: Message: Cyclic object value.Zerk
O
5

Here is my attempt at an answer. I do only tested it on the search box of google's homepage. I made use of @alecxe's answer above about 'outerHTML' Having obtained the html, I used a regular expression ([a-z]+-?[a-z]+_?)='?"? to match the attribute names. I think the regex would just have to be modified to match an increasing number of cases. But the essential name we need is "whatever is behind the equal sign."

Given a webElement

def get_web_element_attribute_names(web_element):
    """Get all attribute names of a web element"""
    # get element html
    html = web_element.get_attribute("outerHTML")
    # find all with regex
    pattern = """([a-z]+-?[a-z]+_?)='?"?"""
    return re.findall(pattern, html)

Test it on the below code

import re
from selenium import webdriver

driver = webdriver.Firefox()
google = driver.get("http://www.google.com")

driver.find_element_by_link_text("English").click()
search_element = driver.find_element_by_name("q")
get_web_element_attribute_names(search_element)

output:

['class', 'id', 'maxlength', 'name', 'autocomplete', 'title', 'value', 'aria-label', 'aria-haspopup', 'role', 'aria-autocomplete', 'style', 'dir', 'spellcheck', 'type']
Overcapitalize answered 17/7, 2017 at 8:20 Comment(1)
outerHtml includes descendantsBooma

© 2022 - 2024 — McMap. All rights reserved.