Reputation: 2661
I have a html element like so:
<table>
<tbody>
<tr>
<td>My Text</td>
<td>Some Other Text</td>
<td><img src="../delete.png" alt="trashcan"></td>
</tr>
<tr>
<td>More Text</td>
<td>Some More Text</td>
<td><img src="../delete.png" alt="trashcan"></td>
</tr>
</tbody>
</table>
I'm want to find a table row by text and then click the trashcan icon to delete it.
So my idea is to loop over the rows <tr/>
and then loop over the cells <td/>
. If the text matches the cell text, find the image from that row by XPATH
and then click it.
tbody = driver.find_element_by_tag_name("tbody")
tr = tbody.find_elements_by_tag_name("tr")
for row in tr:
td = row.find_elements_by_tag_name("td")
print(len(td))
for cell in td:
if cell.text == "More Text":
delete = row.find_element_by_xpath('//img[@alt="trashcan"]')
delete.click()
My understanding is that driver
is the entire page. tbody
is just the tbody element in that page. So whatever I try to locate from there has to be a child of that element. To confirm I print out the length of the td
elements which is prints out "3".
The delete button delete = row.find_element_by_xpath('//img[@alt="trashcan"]')
selects the delete button from the first table row instead of from the second row.
I also tried
delete = row.find_elements_by_xpath('//img[@alt="trashcan"]')
delete[0].click()
But it also selects the row.
Just to be sure I printed out the row (print(row.get_attribute("innerHTML"))
in the if condition and it prints out the second row.
Any ideas what's going on or how I could select the img
in the second row instead?
Upvotes: 1
Views: 885
Reputation: 3433
You can try to change the for loop. Like for i in range(1,len(tr)):
It skips the 1st tr
.
Or you can pop
the 1st element in tr
before for loop.
Upvotes: 1
Reputation: 4212
You can find the correct XPath with text() method like this:
//td[contains(text(),'Some More Text')]/../td[3]
Or:
//td[contains(text(),'Some More Text')]/parent::tr/td[3]
The first one just goes one level up and then looks for the third td element.
The second approach looks the parent element, like described here XPath: Get parent node from child node.
Try to apply it to your loop.
Upvotes: 2
Reputation: 452
find_element_by_xpath
is only going to give you the first path it finds.
I'm not sure how familiar you are with JavaScript, but I tend to use find_elements_by_css_selector
. It lets you then put in the same argument that you would when you run document.querySelectorAll
.
In your case, you can do:
text_to_find = 'If this is spotted, then delete'
# Find all tds
trs = driver.find_elements_by_css_selector("td")
# Iterate over each tr insde a td.
for tr in trs:
for td in tr.find_elements_by_css_selector('tr'):
# If any td text is equal to the text you wish to delete, then click on the trashcan and then move onto the next td.
if td.text == text_to_find:
tr.find_element_by_css_selector("[alt='trashcan']").click() # notice that I removed the 's' in elements.
break
Upvotes: 1