Web Table in Selenium Python Bindings

Python Selenium bindings is highly flexible to extend the features and commands to build a scalable test automation framework.

But Why do we need Custom WebElements in Selenium python ?
Sometimes we may want access few webelement like tables, bootstrap dropdowns and so on, during those time we tend to write the complete code every time, or we call some method to perform operation but in longer run this way doing becomes more and more difficult to handle.

But if we create Custom Webelements helps us to ease the process and as well as narrows down the learning curve.

This tutorial focuses on how to create custom webelements by extending selenium class

Custom WebTable's test table

Website Title Field
Chercher.tech chercher Future Technologies
selenium-webdriver.com Selenium Webdriver Automation Testing
google.com Google Search Engine
facebook.com Facebook Social Media

Custom WebTable in Selenium Python bindings

WebElement interface in Selenium provides methods to perform operations on the various webelements.

Python Selenium provides helper classes to work with the dropdown element which is formed using select HTML tag. Anyways selenium python doesnot support the tables on webpage or the <table> elements

We will be using WebElement functions to perform operations on Webtable, we will be considering the web table is formed using <table>, <tr>, <td> HTML tags.

WebTable Methods :
To access the details of the WebTable we may need implement few methods like:

  • Accept WebTable element
  • Get number of rows
  • Get number of columns
  • Get the size of the table
  • Get all the data from a row
  • Get all the date from column
  • Get the total data
  • Verify Presence of Data
  • Get data from Specific cell


1. Accept WebTable Element : We need to accept the table on which we are going to perform the operations. We will be accepting the webtable as parameter for the WebTable() constructor.

Constructor assigns the Webtable element into global non-static variable table, we are assignig the value into global as we want to use the value across the class.


// accept the web element (table) as parameter to then constructor
def __init__(self, webTable):
    self.table = webTable


2. Get number of Rows : Sometimes user may request for number of rows present in the table, in such cases we should be able to give details. tr tags are used to form the table rows in HTML, so if we can get the number of tr present in our table element then we got our number of rows.

We have subtracted 1 from the total size because all the rows including header are also formed using tr HTML tags, so we subtracted 1 to exclude the headers.We are returning the size to calling method.


def get_row_count(self):
    return len(self.table.find_elements_by_tag_name("tr")) - 1;


3. Get number of Columns : We can give the count of columns present in the table by counting the number of td HTML tags present in the table, tdHTML tags are used to form the cells. We have used xpath //tr[2]/td for find the number of columns, If we use //tr[1] then we may need to use th HTML tags as tr[1] point to headers and header will not have the td tags.


// get the number of columns present
def get_column_count(self):
    return len(self.table.find_elements_by_xpath("//tr[2]/td"));


4. Get the size of the table : Few people may expect out WebTable element to give the details about the total size of the table instead of giving number of rows, number of columns seperately. In this case we may need to return the Map of Key Value pairs which contains count of rows and columns.

Instead of creating new method implementation we cab use the get_row_count, get_column_count to get the row count and column count. This methods returns a Map of values, Map consists String as keys and Integer as Value.


def get_table_size(self):
    return {"rows": self.get_row_count(),
            "columns": self.get_column_count()}


5. Get all the data from a Row : Sometimes user may request the WebTable class to get a particular row values, we can get the row values by iterating the all the td HTML elements present under that row.

This method gets the all the td HTML element from a specific row, and iterates those element to store the text from it. We would be adding the text into list, so we can return the list at the end of the method.

We want to exclude the header and xpath index starts from 1, so we are adding +1 to the user passed value. We have throw the throw the exception when user passes 0 as value as all rows starts from 1.


// get row data and return it as list
def row_data(self, row_number):
	if(row_number == 0):
		raise Exception("Row number starts from 1")
	
	row_number = row_number + 1;
	row = self.table.find_elements_by_xpath("//tr["+str(row_number)+"]/td");
	rData = [];
	for webElement in row :
		rData.append(webElement.text);
	
	return rData;


6. Get all the data from a Column : Similar to a row, user may need the values from a particular column. To get the values from column we need to get all the td HTML elements based on the column number passed in the method.

In this case, we will be just iterating only cell, //tr/td avoids the headers so no need perform any action regarding that, but we still have to throw exception when user passes 0.


// get the column data and return as list
def column_data(self, column_number):
	col = self.table.find_elements_by_xpath("//tr/td["+str(column_number)+"]");
	rData = [];
	for webElement in col :
		rData.append(webElement.text); 
	return rData;


7. Get the total data : When we design a web table in Selenium WebDriver we must be in a position that we should be able to return all the data present in the table in Map format.

All the rows in a HTML table are formed using tr tags, and all the columns are formed using td tags. If there are 10 columns present under row in a webtable, which means there are 10 td tags are present under the tr tag

To get all the data from the table we have to iterate each and every row present under the web table, once we get the rows we must iterate the td tags present under that particular row

Idea of below code is, we have to iterate over all the data present in the table by iterating row by row using loops in selenium webdriver.

  • This method does not accept any parameters
  • We have to find how may rows are present excluding the Headers. (we are subtracting one in noOfRows).
  • We have to find the number of columns present, we can use //tr[2]/td xpath to do so.
  • Based one number of rows we have to form outer loop, and based on the number of columns we have to form inner loop.
  • Create a list to accept all the values of rows, we should give ability to user that he/she can to extract only first if she want so. To give such a result we have to use List of Lists.
  • Inside the first loop create another list variable, so when ever it crosses this line it should be created newly
  • Get the text values from inner loop and add it to the 'ro' list
  • After inner loop add the 'ro' list into 'allData' list.
  • return the values of 'allData' List

// get all the data from the table
def get_all_data(self):
	# get number of rows
	noOfRows = len(self.table.find_elements_by_xpath("//tr")) -1;
	# get number of columns
	noOfColumns = len(self.table.find_elements_by_xpath("//tr[2]/td"));
	allData = [];
	# iterate over the rows, to ignore the headers we have started the i with '1'
	for i in range(2, noOfRows):
		# reset the row data every time
		ro = [];
		# iterate over columns
		for j in range(1, noOfColumns) :
			# get text from the i th row and j th column
			ro.append(self.table.find_element_by_xpath("//tr["+str(i)+"]/td["+str(j)+"]").text);
		
		# add the row data to allData of the self.table
		allData.append(ro);
	
	return allData;


8. Verify presence of given data : We also should give an option to the user to check whether a particular data is present in the table or not, we can use xpath to verify whether given data is present or not by using the text() function with the xpath in selenium webdriver

There could be more than one data matching so we have used find_elements method to find how many elements present. if one or more elements present this method returns true but this methods returns false if number of elements is 0


// verify presence of the text/data
def presence_of_data(self, data):
        
	# verify the data by getting the size of the element matches based on the text/data passed
	dataSize = len(self.table.find_elements_by_xpath("//td[normalize-space(text())='"+data+"']"))
	presence = false;
	if(dataSize > 0):
		presence = true;
	return presence; 


9. Get data from Specific Cell : We should return the data from spcific cell when user requests, we can do it form the right xpath.

We have to exclude the Header row for that we would be adding +1 to the row requested by the user.


// get the data from a specific cell
def get_cell_data(self, row_number, column_number): 
	if(rowNumber == 0):
		raise Exception("Row number starts from 1");
	
	rowNumber = rowNumber+1;
	cellData = table.find_element_by_xpath("//tr["+str(row_number)+"]/td["+str(column_number)+"]").text;
	return cellData;


Complete program for Custom Webelement 'WebTable'


from selenium import webdriver     


class WebTable:
    def __init__(self, webtable):
       self.table = webtable
    
    def get_row_count(self):
      return len(self.table.find_elements_by_tag_name("tr")) - 1;
    
    def get_column_count(self):
        return len(self.table.find_elements_by_xpath("//tr[2]/td"));
       
    def get_table_size(self):
        return {"rows": self.get_row_count(),
                "columns": self.get_column_count()}
       
    def row_data(self, row_number):
        if(row_number == 0):
            raise Exception("Row number starts from 1")
        
        row_number = row_number + 1;
        row = self.table.find_elements_by_xpath("//tr["+str(row_number)+"]/td");
        rData = [];
        for webElement in row :
            rData.append(webElement.text);
        
        return rData;
       
    def column_data(self, column_number):
        col = self.table.find_elements_by_xpath("//tr/td["+str(column_number)+"]");
        rData = [];
        for webElement in col :
            rData.append(webElement.text); 
        return rData;
    
    def get_all_data(self):
        # get number of rows
        noOfRows = len(self.table.find_elements_by_xpath("//tr")) -1;
        # get number of columns
        noOfColumns = len(self.table.find_elements_by_xpath("//tr[2]/td"));
        allData = [];
        # iterate over the rows, to ignore the headers we have started the i with '1'
        for i in range(2, noOfRows):
            # reset the row data every time
            ro = [];
            # iterate over columns
            for j in range(1, noOfColumns) :
                # get text from the i th row and j th column
                ro.append(self.table.find_element_by_xpath("//tr["+str(i)+"]/td["+str(j)+"]").text);
            
            # add the row data to allData of the self.table
            allData.append(ro);
        
        return allData;
       
    def presence_of_data(self, data):
        
        # verify the data by getting the size of the element matches based on the text/data passed
        dataSize = len(self.table.find_elements_by_xpath("//td[normalize-space(text())='"+data+"']"))
        presence = false;
        if(dataSize > 0):
            presence = true;
        return presence; 
    
    def get_cell_data(self, row_number, column_number): 
        if(rowNumber == 0):
            raise Exception("Row number starts from 1");
        
        rowNumber = rowNumber+1;
        cellData = table.find_element_by_xpath("//tr["+str(row_number)+"]/td["+str(column_number)+"]").text;
        return cellData;


Test Custom WebTable : We have to test our Selenium bindings Custom element before we use it in framework, lets test it.

We will be using the table present in the top of this page. I hope the test code is pretty simple, please comment in the if you have troup in understanding.


class Test(unittest.TestCase):
    def test_web_table(self):
        driver = webdriver.Chrome(executable_path=r'D:\PATH\chromedriver.exe');
        driver.implicitly_wait(30)
                                               
        driver.get("https://chercher.tech/python/table-selenium-python");
        w = WebTable(driver.find_element_by_xpath("//table[@id='webtable']"));
        
        print("No of rows : ", w.get_row_count());
        print("------------------------------------");
        print("No of cols : ", w.get_column_count());
        print("------------------------------------");
        print("Table size : ", w.get_table_size());
        print("------------------------------------");
        print("First row data : ", w.row_data(1));
        print("------------------------------------");
        print("First column data : ", w.column_data(1));
        print("------------------------------------");
        print("All table data : ", w.get_all_data());
        print("------------------------------------");
        print("presence of data : ", w.presence_of_data("Chercher.tech"));
        print("------------------------------------");
        print("Get data from Cell : ", w.get_cell_data(2, 2));
       
        
                    
if __name__ == "__main__":
    unittest.main()

About Author

Myself KarthiQ, I am the author of this blog, I know ways to write a good article but some how I donot have the skills to make it to reach people, would you like help me to reach more people By sharing this Article in the social media.

Share this Article Facebook
You can also share knowledge by Adding a topic here


Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions

Recent Addition

new tutorial Protractor Online Training : We have closed registration for training

Please do email to chercher.tech@gmail.com for any queries

If you already registered then please do check your email for the Webex link for the training starting from 15th Nov 2018
 
Join My Facebook Group
Join Group