0

I am working on a bot for a website and it requires a color and keyword to find the item. I am using selenium to look for the item from the keyword and then pick a color option (some items on the website, provide the item in multiple colors). I am having trouble looking for both the keyword and color at the same time, and then after choosing the correct colored version of the item from the user's color and keyword input. I want it to select on that option.

Formula I am trying to make in Python:

 If the first Xpath(keyword) is found and the 2nd Xpath(color) is found
 Then select on the item that contains those 2 properties.

This is the current code I have:

 Item = driver.find_element_by_xpath('//*[contains(text(), "MLK")]' and contains ("Black")]')

if (item != None):
    actions.moveToElement(item).click()

I've tried the code above and it doesn't work.

Here are the 2 pieces of code that I want to merge to find the item:

  1. driver.find_element_by_xpath('//a[contains(text(), "MLK")]')

  2. driver.find_element_by_xpath('//a[contains(text(), "Black")]')

The keyword is called MLK

The Color is called Black

After Merging, I want to find that Exact Element (Called MLK, Color version = Black)

This combined item should be clicked on, I only know to use .click() If a better way, please let me know.


The website I am using to make a bot for: supremenewyork.com The item I am using as an example, to pick a certain color (It's the Sweatshirt with MLK on it): http://www.supremenewyork.com/shop/all/sweatshirts

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
sniperipp
  • 13
  • 3

3 Answers3

0

Try union "|" operator to combine two xpath.

Example:-

//p[@id='para1'] | //p[@id='para2']

('//a[contains(text(), "MLK")]' | '//a[contains(text(), "Black")]')
sunny_teo
  • 1,961
  • 1
  • 7
  • 11
  • I still get an error saying: driver.find_element_by_xpath('//a[contains(text(), "Black")' | '//a[contains(text(), "MLK")]').click() TypeError: unsupported operand type(s) for |: 'str' and 'str' – sniperipp Apr 15 '18 at 12:46
0

You can use a full XPath to select the item you want based on two conditions, you just need to start from a parent node and then apply the conditions on the child nodes:

//div[contains(./h1/a/text(), "MLK") and contains(./p/a/text(), "Black")]/a/@href

You first need to select the element itself, after that you need to get the attribute @href from the element, something like this:

Item = driver.find_element_by_xpath('//div[contains(./h1/a/text(), "MLK") and contains(./p/a/text(), "Black")]/a')
href = Item .get_attribute("href")
Ayoub_B
  • 702
  • 7
  • 19
  • selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: The result of the xpath expression "//div[contains(./h1/a/text(), "MLK") and contains(./p/a/text(), "Black")]/a/@href" is: [object Attr]. It should be an element. – sniperipp Apr 15 '18 at 13:26
  • How would you make it so it also clicks on that particular item? Cause i get this error: – sniperipp Apr 15 '18 at 13:40
  • href = Item .get_attribute("href").click() AttributeError: 'unicode' object has no attribute 'click' – sniperipp Apr 15 '18 at 13:41
  • If you have the href you can navigate to it directly, if you want to click on the 'a' node then you can just do: Item.click() without the need to get the 'href' – Ayoub_B Apr 15 '18 at 13:48
  • It's not navigating to it then. Do you have a discord, I can contact you faster? @Ayoub_B – sniperipp Apr 15 '18 at 13:50
  • Are you getting any errors? And unfortunately I don't – Ayoub_B Apr 15 '18 at 13:54
  • I am not getting errors. But it's not clicking on the item – sniperipp Apr 15 '18 at 13:54
  • Here's part: driver.get("http://www.supremenewyork.com/shop/all/sweatshirts") Item = driver.find_element_by_xpath('//div[contains(./h1/a/text(), "MLK") and contains(./p/a/text(), "Black")]/a') href = Item .get_attribute("href") href.click() – sniperipp Apr 15 '18 at 13:56
  • I see: You need to do Item.click() and not href.click() – Ayoub_B Apr 15 '18 at 13:57
  • Just ignore the href for now. and only use Item. – Ayoub_B Apr 15 '18 at 13:57
  • Ok. Thanks it works. But also how would you write that in a If statement, so that if it doesn't find the item, it just refreshes the page? – sniperipp Apr 15 '18 at 14:01
  • After selecting the element you can do: if Item: Item.click else driver.get("supremenewyork.com/shop/all/sweatshirts") but you should put this inside a loop. – Ayoub_B Apr 15 '18 at 14:07
  • It doesn't refresh. I changed the Name of the item, so it can't find it, and it comes up with this. Message: no such element: Unable to locate element: {"method":"xpath","selector":"//div[contains(./h1/a/text(), "MLKS") and contains(./p/a/text(), "White")]/a"} – sniperipp Apr 15 '18 at 14:10
  • You need to wrap the selection in a try catch statement, refer to this: https://stackoverflow.com/questions/9567069/python-selenium-webdriver-checking-element-exists – Ayoub_B Apr 15 '18 at 14:38
  • I apologize, I am kinda new to this. Could you help me wrap it in a try catch statement? When reading that, it's confusing for me. – sniperipp Apr 15 '18 at 14:40
  • i need help @Ayoub_B – sniperipp Apr 15 '18 at 15:15
  • @sniperipp I don't have much experience in Python, you might want to place that as a new question. – Ayoub_B Apr 15 '18 at 17:24
0

It took me a second to realize that there are 3 A tags for each shirt... one for the image, one for the name of the shirt, and one for the color. Since the last two A tags are the ones you are wanting to text search, you can't look for both strings in the same A tag. I've tested the XPath below and it works.

//article[.//a[contains(.,'MLK')]][.//a[.='Black']]//a

ARTICLE is the container for the shirt. This XPath is looking for an ARTICLE tag that contains an A tag that contains 'MLK' and then another A tag that contains 'Black' then finds the A tags that are descendants of the ARTICLE tag. You can click on any of them, they are all the same link.

BTW, your code has a problem. The first line below will throw an exception if there is no match so the next line will never be reached to test for None.

Item = driver.find_element_by_xpath('//*[contains(text(), "MLK")]' and contains ("Black")]')
if (Item != None):
    actions.moveToElement(item).click()

A better practice is to use .find_elements() (plural) and check for an empty list. If the list is empty, that means there was no element that matched the locator.

Putting the pieces together:

items = driver.find_elements_by_xpath("//article[.//a[contains(.,'MLK')]][.//a[.='Black']]//a")
if items:
    items[0].click()

I'm assuming you will be calling this code repeatedly so I would suggest that you put this in a function and pass the two strings to be searched for. I'll let you take it from here...

JeffC
  • 22,180
  • 5
  • 32
  • 55
  • Hey @JeffC could you help me so that the code you provided above for clicking the item works like this, but does it forever until IF statement condition is true? If elements found then click on item else refresh the page – sniperipp Apr 15 '18 at 22:26