Python Многопоточный селен - PullRequest
0 голосов
/ 29 апреля 2020

Я пишу код в Tkinter с кнопкой, которая запускает 6 экземпляров chrome селена, каждый из которых имеет свой URL. Цель состоит в том, чтобы драйверы запускались как можно быстрее, и каждый экземпляр драйвера должен повторно вводить свой указанный c url (refre sh) каждые 4 секунды. Каждый драйвер связан с классом, который содержит требуемый URL. Я пробовал это с потоками:

import tkinter as tk
import threading
import os
import time

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

browsers = []

class Browser:
    def __init__(self, url, session_file):
        self.url = url
        self.session_file = session_file


def manipulate_browser(browser):

    browser.driver = webdriver.Chrome(ChromeDriverManager().install())

    while True:
        browser.driver.get(browser.url)
        time.sleep(4)



def start_browsers():

    for browser in browsers:
        browser.thread = threading.Thread(target=manipulate_browser, args=(browser,))
        browser.thread.start()


if __name__=='__main__':
    lock = threading.Lock()
    threads = []
    urls = 'https://google.com', 'https://facebook.com', 'https://instagram.com', 'https://snapchat.com', 'https://stackoverflow.com', 'https://amazon.com', 'https://microsoft.com'#, 'https://stackoverflow.com', 'https://youtube.com', 'https://yahoo.com'
    for url in urls:
        session_file = 'session_' + ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(10))
        newBrowser = Browser(url, session_file)
        browsers.append(newBrowser)


    root = tk.Tk()                    
    button_start_browsers = tk.Button(root, command=start_browsers, width=50, height=4, bg='red', text='Start Browsers')
    button_start_browsers.pack()

И это прекрасно работает, но я хочу добавить некоторые опции и возможности в драйвер в функции manipulate_browser. Вот так:

import tkinter as tk
import threading
import os
import time
import random, string

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from multiprocessing.pool import ThreadPool

browsers = []

class Browser:
    def __init__(self, url, session_file):
        self.url = url
        self.session_file = session_file


def manipulate_browser(browser):
    global lock
    with lock:
        caps = DesiredCapabilities().CHROME
        caps["pageLoadStrategy"] = "none"

        chrome_options = webdriver.ChromeOptions();

        current_dir = os.path.dirname(os.path.abspath(__file__))
        os.mkdir(current_dir + '\\' + browser.session_file) 
        chrome_options.add_argument(r'--user-data-dir=' + current_dir + '\\' + browser.session_file + '\\selenium')

        chrome_options.add_argument("--window-size=750,750")

    browser.driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options, desired_capabilities=caps)

    while True:
        browser.driver.get(browser.url)
        time.sleep(4)



def start_browsers():

    for browser in browsers:
        browser.thread = threading.Thread(target=manipulate_browser, args=(browser,))
        browser.thread.start()


if __name__=='__main__':
    lock = threading.Lock()
    threads = []
    urls = 'https://google.com', 'https://facebook.com', 'https://instagram.com', 'https://snapchat.com', 'https://stackoverflow.com', 'https://amazon.com', 'https://microsoft.com'#, 'https://stackoverflow.com', 'https://youtube.com', 'https://yahoo.com'
    for url in urls:
        session_file = 'session_' + ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(10))
        newBrowser = Browser(url, session_file)
        browsers.append(newBrowser)


    root = tk.Tk()                    
    button_start_browsers = tk.Button(root, command=start_browsers, width=50, height=4, bg='red', text='Start Browsers')
    button_start_browsers.pack()

После реализации это больше не работает: имеется в виду: иногда я получаю эту ошибку selenium.common.exceptions.WebDriverException: Message: unknown error: cannot parse internal JSON template: Line: 1, column: 1, Unexpected token. И все потоки работают только на одном драйвере (последнем) , Я полагаю, что это потому, что потоки смешиваются друг с другом, поэтому я должен использовать блокировку, но помещение этой строки browser.driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options, desired_capabilities=caps) под блокировку сильно повлияет на мою скорость, которая мне нужна. Я также понимаю, что я должен использовать ThreadPool, чтобы избежать смешивания потоков, и я попробовал это, но приложение GUI зависло. Другой вариант, который предлагают другие, - реализация очереди с потоками, с которой я не очень знаком. Я также думал о попытке многопроцессорной обработки, но максимальное количество процессов зависит от характеристик каждой машины, от моего понимания, и, возможно, я хочу запустить больше процессов, чем это. Как я могу обойти эту ситуацию, чтобы достичь своей цели? Каков наилучший способ?

(Примечание: я провел много исследований относительно своей проблемы, но все еще не мог понять ее. Любая помощь приветствуется!)

РЕДАКТИРОВАТЬ: Из-за многократного тестирования я понял, что строка chrome_options.add_argument(r'--user-data-dir=' + current_dir + '\\' + browser.session_file + '\\selenium') может вызвать все проблемы. Эта строка хранит все chrome сессии в одном значке, и мне очень нравится эта функция, и я не хотел бы от нее избавляться. Как я могу преодолеть проблему, зная эту информацию? Любая помощь будет оценена!

...