4

I want to open and login 5 tabs concurrently without delay in between in tabs. I have tried:

import threading
import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def openurl(threadId):
    print(threading.currentThread().getName(),' Thread')
    url = ('https://www.facebook.com/')
    print(url)
    driver.execute_script("window.open('{0}')".format(url))
    #driver.title(threadId)
    time.sleep(0.1)

    driver.set_window_size(920, 680)
    driver.find_element(By.ID, "email").send_keys("xx")
    driver.find_element(By.ID, "pass").send_keys("yy")
    driver.find_element(By.ID, "loginbutton").click()


if __name__=='__main__':
    driver = webdriver.Chrome()
    windows_before  = driver.current_window_handle
    for i in range(5):
        t1 = threading.Thread(name=i,target=openurl, args=(i,))
        t1.start()
        t1.join()

but it is throwing:

Traceback (most recent call last): File "C:\Users\1024983\AppData\Local\Programs\Python\Python37\lib\threading.py", line 870, in run self._target(*self._args, **self._kwargs) File "C:\Users\1024983\AppData\Local\Programs\Python\Python37\fb-thread.py", line 30, in openurl driver.find_element(By.ID, "email").send_keys("xx") File raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="email"]"} (Session info: chrome=78.0.3904.108)

If I increased sleep time, there is a delay in-between tabs. I tried to navigate using driver.title but my case title is same for all tabs.

Anirban166
  • 3,162
  • 4
  • 11
  • 27
Divya Mani
  • 113
  • 11
  • 1
    You can use wait for object to appear to be sure on the object appearance in a given time limit: https://stackoverflow.com/a/20903328/12422518 – furkanayd Dec 18 '19 at 07:54
  • 1
    [This](https://stackoverflow.com/questions/18150593/selenium-multiple-tabs-at-once/18150682) might be helpful – Shijith Dec 18 '19 at 08:01
  • can you help me to create "instances of webdriver" @Shijith – Divya Mani Dec 18 '19 at 08:45
  • always put full error message (starting at word "Traceback") in question (not comment) as text (not screenshot). There are other useful information. – furas Dec 18 '19 at 08:48
  • this code `driver = webdriver.Chrome()` creates instance of webdriver – furas Dec 18 '19 at 08:51
  • now i edited my error @furas and driver = webdriver.Chrome() this creates different browse..but i want to create different tab – Divya Mani Dec 18 '19 at 08:52
  • I think its explained on the accepted answer of the link `If you are wanting to have multiple threads all act on the same driver instance, but different tabs, that is NOT possible.` – Shijith Dec 18 '19 at 09:03
  • Using this also driver = webdriver.Chrome() i am getting same error..taking time to load url if i give time.sleep(2)..again it is sequential only, not parallel multi threading @Shijith..Is there any other way ? – Divya Mani Dec 18 '19 at 09:11
  • threads in Python doesn't run at the same time because of `GIL` - you could in main thread first open many browsers, load pages and fill login forms and after filling all forms click all buttons. It would have smaller delay when you click all buttons almost at the same time. – furas Dec 18 '19 at 09:17
  • `driver = webdriver.Chrome()` creates instance of webdriver (as you asked) and every instance means separted browse but maybe it will better to control separated browser. But if you use tabs or separated browser problem is always the same - to synchronize threads (or processes) so they will click button at the same moment. – furas Dec 18 '19 at 09:36
  • clicking the button at same moment..atleast this is what i need..i created driver = webdriver.Chrome() inside loop and sent as a parameter still getting error..can you please modify my code for **clicking the button at same moment in all browser instance** please.. – Divya Mani Dec 18 '19 at 09:45
  • Any body please help me to modify my code for **clicking the button at same moment in all browser instance** please.. – Divya Mani Dec 18 '19 at 10:17

1 Answers1

2

It is example uses threads to run separated browsers which fill form and set True in list buttons to inform that login button is ready to click. When all browsers set True in list buttons then all of them click buttons.

It seems that it runs amost a the same time - maybe only system has some to makes so many connections at the same time.

I used list buttons to synchronize all threads. Every thread get number to have own place in list. I don't use append(True) because I'm not sure it can be thread-safe.

import time
from selenium import webdriver
from threading import Thread

def func(number):
    driver = webdriver.Chrome()
    #driver.set_window_size(920, 680)
    driver.get(url)

    driver.find_element_by_id("email").send_keys("xx")
    driver.find_element_by_id("pass").send_keys("yy")
    b = driver.find_element_by_id("loginbutton")

    buttons[number] = True
    print(buttons)

    # wait for other buttons
    while not all(buttons):
        pass

    print('click', number)
    b.click()

# ---

url = 'https://www.facebook.com/'

number_of_threads = 5

#buttons = [False * number_of_threads] # create place 
buttons = []

threads = []

for number in range(number_of_threads):
    t = Thread(target=func, args=(number,)) # get number for place in list `buttons`
    t.start()
    threads.append(t)
    buttons.append(False) # create place 

for t in threads:
    t.join()

EDIT: The same with threading.Barrier(5) and 5 threads will have to run barrier.wait() to move forward.

import time
from selenium import webdriver
from threading import Thread, Barrier

def func(barrier):

    driver = webdriver.Chrome()
    #driver.set_window_size(920, 680)
    driver.get(url)

    driver.find_element_by_id("email").send_keys("xx")
    driver.find_element_by_id("pass").send_keys("yy")
    b = driver.find_element_by_id("loginbutton")

    print('wait for others')
    barrier.wait()

    print('click')
    b.click()

# ---

url = 'https://www.facebook.com/'

number_of_threads = 5

barrier = Barrier(number_of_threads)

threads = []

for _ in range(number_of_threads):
    t = Thread(target=func, args=(barrier,)) 
    t.start()
    threads.append(t)

for t in threads:
    t.join()
furas
  • 95,376
  • 7
  • 74
  • 111
  • Thank you so much..I enhanced this same program if i load the dynamic url which is in excel,it is taking last url only.. My code : number_of_threads = sheet.nrows url=sheet.cell_value(i, 0).. – Divya Mani Dec 18 '19 at 12:17
  • 1
    I don't know what you try to do but maybe you should send url as parameter to thread. – furas Dec 18 '19 at 13:16