S. Wasta
S. Wasta

Reputation: 638

Selenium + Python how to listen for change of element

The idea is to create a bot to read message from a chat, and all message are in a ul>li(not neccesary to write message), e.g

<ul class="message-list">
  <li class="message">
   Hello There
  </li>
  <li class="message">
   Hello
  </li>
</ul>

I found expected_conditions from Selenium, to handle if element exist/found, but it's always true, because there is a message but I don't want to continue the code if a message was already in chat, that's not the main idea. And after that, I found EventFiringWebDriver, AbstractEventListener and nothing.

from selenium import webdriver as wb
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
from selenium.webdriver.common.keys import Keys


class MyListener(AbstractEventListener):
    def before_navigate_to(self, url, driver):
        print("Before navigate to %s" % url)

    def after_navigate_to(self, url, driver):
        print("After navigate to %s" % url)


driver = wb.Chrome('C:\python\selenium\chromedriver.exe')
wait = WebDriverWait(driver, 300)
# ef_driver = EventFiringWebDriver(driver, MyListener())
driver.implicitly_wait(15)
driver.get('https://socket.io/demos/chat/')
driver.switch_to.frame(driver.find_element_by_class_name('iframe-class'))
InputName = driver.find_element_by_xpath('/html/body/ul/li[2]/div/input')
InputName.send_keys('MyNameIsJeff')
InputName.send_keys(Keys.ENTER)


Upvotes: 4

Views: 9821

Answers (2)

0xM4x
0xM4x

Reputation: 470

I think you can write a loop and inside the loop, get the number of "li"s inside the desired "ul". if the number of "li"s increased, you have a new message.

# get list of li inside of ul
ulList = driver.find_elements_by_xpath("//ul[@class='message-list']")
lenOfLis = len(ulList)

# wait for new message...
while (true):

    ulList = driver.find_elements_by_xpath("//ul[@class='message-list']")

    if (len(ulList) > lenOfLis): # you have new message
        for (i in range(len(ulList)-lenOfLis)):
            yourLastMessage = ulList[-1-(i-1)]
            # you can do whatever you want with your last messages
        LenOfLis = len(ulList) # update length of ul


    # wait 15 seconds 
    sleep(5)

Upvotes: 4

CEH
CEH

Reputation: 5909

You can do some kind of listener in a loop that checks the text of your message elements to determine whether or not it is a new message, you just have to determine a set time frame that you want to wait between 'checks' -- 10 seconds, 30 seconds, 1 minute, etc.

I don't think you need an event listener for this. You can just grab the latest message, then keep checking it to see if it's different than the previous value.

from time import sleep

# get list of currently displayed messages
messages = driver.find_elements_by_xpath("//li[@class='message']")

# get text from most recent message
# depending on element order on the page, might need to do messages.last
last_message_text = messages[0].text

# do something here to trigger a new message coming in?

# wait for last_message_text to be something different
while (true):

    # get list of currently displayed messages
    messages = driver.find_elements_by_xpath("//li[@class='message']")

    # new message has arrived if we hit this statement
    if (messages[0].text != last_message_text) break;

    # wait 15 seconds 
    sleep(15)

This example will grab the list of messages currently displayed. Then, it grabs the last received message. The code enters a loop and re-fetches the list of messages, checks the last received message, and compares its text to the last message value we saved earlier.

If the last received message is different from saved value, the loop will break, meaning a new message has arrived.

There's a few unclear things here -- the most recent message may be either the first element, or last element, in messages list. The other issue -- are you doing something on your end to trigger a new message appearing? Such as InputName.send_keys('MyNameIsJeff')? If this is the case, the order of the code may need to change a bit.

Lastly -- in your comments, you mentioned sometimes the ul is empty. I'm not really sure what this means, but if some messages are appearing and there is no HTML on the page for them, then this solution won't really work.

Upvotes: 2

Related Questions