PySide ожидает сигнала от основного потока в рабочем потоке

Я решил добавить графический интерфейс к одному из моих скриптов. Скрипт представляет собой простой веб-скребок. Я решил использовать рабочий поток, так как загрузка и анализ данных могут занять некоторое время. Я решил использовать PySide, но мои знания Qt в целом довольно ограничены.

Поскольку сценарий должен ожидать ввода пользователя при обнаружении капчи, я решил, что он должен подождать, покаQLineEdit пожарыreturnPressed а затем отправить его содержимое в рабочий поток, чтобы он мог отправить его для проверки. Это должно быть лучше, чем занято - ждать нажатия клавиши возврата.

Кажется, что ожидание сигнала не так просто, как я думал, и после поиска я наткнулся на несколько решений, похожих наэто, Сигнализация между потоками и локальный цикл обработки событий в рабочем потоке усложняют мое решение.

После нескольких часов работы он все равно не будет работать.

Что должно произойти:

Загрузить данные, пока они не будут добавлены в код безопасностиСкачайте капчу и покажите ее пользователю, запуститеQEventLoop позвонив по телефонуself.loop.exec_()ВыходQEventLoop позвонив по телефонуloop.quit() в слоте рабочих потоков, который подключен черезself.line_edit.returnPressed.connect(self.worker.stop_waiting) вmain_window классПроверяйте капчу и цикл в случае сбоя проверки, в противном случае повторите последний URL, который должен быть загружен сейчас, а затем переходите к следующему URL

Что происходит:

... смотри выше ...

ВыходQEventLoop не работаетself.loop.isRunning() возвращаетсяFalse после вызова егоexit(). self.isRunning возвращаетсяTrueкак таковая нить, казалось, не умирала при странных обстоятельствах. Тем не менее нить останавливается наself.loop.exec_() линия. Таким образом, поток застрял, выполняя цикл обработки событий, хотя цикл обработки событий сообщает мне, что он больше не работает.

GUI отвечает так же, как и слоты класса рабочего потока. Я вижу, что текст отправляется в рабочий поток, состояние цикла событий и самого потока, но ничего после того, как вышеупомянутая строка не была выполнена.

Код немного запутанный, поэтому я добавляю немного псевдокод-python-mix, оставляя неважное:

class MainWindow(...):
    # couldn't find a way to send the text with the returnPressed signal, so I
    # added a helper signal, seems to work though. Doesn't work in the
    # constructor, might be a PySide bug?
    helper_signal = PySide.QtCore.Signal(str)
    def __init__(self):
        # ...setup...
        self.worker = WorkerThread()
        self.line_edit.returnPressed.connect(self.helper_slot)
        self.helper_signal.connect(self.worker.stop_waiting)

    @PySide.QtCore.Slot()
    def helper_slot(self):
        self.helper_signal.emit(self.line_edit.text())

class WorkerThread(PySide.QtCore.QThread):
    wait_for_input = PySide.QtCore.QEventLoop()

    def run(self):
        # ...download stuff...
        for url in list_of_stuff:
            self.results.append(get(url))

    @PySide.QtCore.Slot(str)
    def stop_waiting(self, text):
        self.solution = text
        # this definitely gets executed upon pressing return
        self.wait_for_input.exit()

    # a wrapper for requests.get to handle captcha
    def get(self, *args, **kwargs):
        result = requests.get(*args, **kwargs)
        while result.history: # redirect means captcha
            # ...parse and extract captcha...
            # ...display captcha to user via not shown signals to main thread...

            # wait until stop_waiting stops this event loop and as such the user
            # has entered something as a solution
            self.wait_for_input.exec_()

            # ...this part never get's executed, unless I remove the event
            # loop...

            post = { # ...whatever data necessary plus solution... }
            # send the solution
            result = requests.post('http://foo.foo/captcha_url'), data=post)
        # no captcha was there, return result
        return result

frame = MainWindow()
frame.show()
frame.worker.start()
app.exec_()

Ответы на вопрос(2)

Ваш ответ на вопрос