-1

I am running a streamlit app, in which I try to run selenium (click a search box and) inside iframe component, but I keep getting an error "NoSuchElementException".

It successfully opens the iframe on streamlit app, but it does not execute the selenium code inside the iframe. The selenium code itself runs fine when I test it without the iframe, but I can't get it to work inside the iframe.

Here is my code:

import streamlit as st
from dateutil.parser import parse
import streamlit.components.v1 as components
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

st.title("Auto Search App")

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 20)

# url = 'https://wego.here.com/'
# driver.get(url)

components.iframe("https://wego.here.com/", height = 500)

## Give time for iframe to load ##
time.sleep(3)
## You have to switch to the iframe like so: ##
driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))

search_input = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input.input_search")))
search_input.click()
search_input.send_keys('Seattle')
search_input.send_keys(Keys.ENTER)

wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "button.btn"))).send_keys(Keys.ENTER)

internal_search_input = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input#itinerary_item_input_0")))
internal_search_input.click()
internal_search_input.send_keys('Chicago')
internal_search_input.send_keys(Keys.ENTER)

This is the streamlit page with the error message:

1


EDIT: Based on the answer, I figured that I don't have to switch to iframe in order to access the search input element. I guess the problem is due to the fact that when I run "streamlit run app5.py" on cmd, it generates two separate browsers with an empty browser opening most recently, so that the selenium codes is executing on an empty page not on the streamlit localhost:8501 page. How can I not generate the empty browser and only open the localhost:8501 page, so that the selenium code runs on the streamlit page?

2

EDIT2: I added more selenium execution code for your reference. The reason that I am using selenium here is to do some automation done on the iframe so that it populates the navigation page at the end. I was able to get it done on a separate chrome by using driver.get(url) but not on streamlit with iframe. This is the final result I want to see in the iframe:

3

user9532692
  • 584
  • 7
  • 28

3 Answers3

1

The input.input_search element is NOT inside any iframe on that page.
There are 4 iframes there, however the search input is not inside any of them.
So you should not switch to iframe in order to access the search input element.

Prophet
  • 32,350
  • 22
  • 54
  • 79
1

You need to consider a couple of things here.

  • The desired <input> isn't within any <iframe> as such, so you don't need to switch to any frame.

  • To click() on any clickable element instead of presence_of_element_located() you need to induce WebDriverWait for the element_to_be_clickable() and you can use the following Locator Strategy:

  • Code Block:

    driver.get("https://wego.here.com/")
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.input_search"))).send_keys("Seattle" + Keys.RETURN)
    
  • Browser Snapshot:

Seattle

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • I was also able to execute selenium by opening up a browser with the wego.here.com url like what you have done with **driver.get("https://wego.here.com/")**. However, I want to run the selenium in an iframe on streamlit app. I figured I don't have to switch to iframe in order to access the search input element. But I guess the issue has to do with it opening two browser tabs with an empty one opening at last, so that the selenium is running on an empty page. How can I only open the localhost:8501 page not an empty page, so that the selenium code runs on the streamlit page? – user9532692 Dec 09 '21 at 18:07
1

From your code i understand that you are trying to run the selenium code to set the value of the input in the iframe inside the Streamlit page that opens.

This is not possibble. I will try to explain using the order of events when you run this code.

With your current code this is what happens:

  1. you run the streamlit run app.py command.
  2. Streamlit opens this code in a chrome browser.
  3. The selenium code starts running and because you don't use driver.get(url) it runs on an empty page causing the NoSuchElementException.

If you use the driver.get(url) and set the url to the Streamlit app url='http://localhost:8501/' then it also wont work because this is what happens:

  1. you run the streamlit run app.py command.
  2. Streamlit opens this code in a chrome browser.
  3. The selenium code starts running and opens a new chrome tab of the selenium code and you cant make selenium get an already opened tab (session).

I would suggest not using selenium for this and to create a text_input using Streamlit and generate the iframe using the geolocation of the input.

Code:

import streamlit as st
import streamlit.components.v1 as components
from geopy.geocoders import Nominatim

bt = st.text_input("Enter Location")

if bt:
    geolocator = Nominatim(user_agent="my_app")
    location = geolocator.geocode("Seattle")
    components.iframe(f"https://wego.here.com/?map={location.latitude},{location.longitude},18,normal&x=ep", height = 500)

Output:

Example


Edit 1 - if you just want to view direction from Chicago to Seattle this can be done by changing only the url.

code:

import streamlit as st
import streamlit.components.v1 as components
from geopy.geocoders import Nominatim

components.iframe("https://wego.here.com/directions/mix/Chicago/Seattlel", height = 500)

Output:

Output 2

RoseGod
  • 1,206
  • 1
  • 9
  • 19
  • 1
    Thanks for your feedback, but I am not trying to get just the map of seattle, but I want to get a navigation map from Chicago to Seattle by using selenium. I wonder if there is a way to play with the url to get a navigation map from Chicago to Seattle without using selenium. I edited my post at the end and my code for your reference. – user9532692 Dec 09 '21 at 22:27
  • @user9532692 I edited my answer based in your requirements, you can just play with the url to get what you want no need for selenium. – RoseGod Dec 09 '21 at 22:50
  • **How/Where did you get that url?** This is what I thought of in the first place, but I could not find the url that would take city names as input values to get directions. That's why I tried to do it with selenium, but this is the cleanest and easiest way! – user9532692 Dec 10 '21 at 02:45
  • @user9532692 I just used the website, I inserted the directions and saw how the url changes. This is not the most stable solution but it's better than using selenium inside you Streamlit app. Also maybe try searching for different map services that have an api that you can use instead of using the url directly :) – RoseGod Dec 10 '21 at 08:52
  • Could you elaborate more on how you see the url changes. Do you turn on DevTools on browser to see such changes? Because I don't see a clean url on my browser when I insert the directions. – user9532692 Dec 10 '21 at 19:11
  • I just saw the url changes to "https://wego.here.com/directions/mix/Current_location/Destination?Configurations" so i used this to create the link. – RoseGod Dec 10 '21 at 19:22