PySide espera la señal del hilo principal en un hilo de trabajo

Decidí agregar una GUI a uno de mis scripts. El script es un simple raspador web. Decidí usar un subproceso de trabajo ya que la descarga y el análisis de los datos pueden llevar un tiempo. Decidí usar PySide, pero mi conocimiento de Qt en general es bastante limitado.

omo se supone que el script debe esperar la entrada del usuario al encontrarse con un captcha, decidí que debería esperar hasta unQLineEdit incendiosreturnPressed y luego envíe su contenido al subproceso de trabajo para que pueda enviarlo para su validación. Eso debería ser mejor que estar ocupado esperando que se presione la tecla de retorno.

arece que esperar una señal no es tan sencillo como pensé que sería y después de buscar por un tiempo encontré varias soluciones similares aest. Sin embargo, la señalización a través de subprocesos y un bucle de evento local en el subproceso de trabajo hace que mi solución sea un poco más complicada.

Después de jugar con él durante varias horas, todavía no funcionará.

Qué se supone que sucederá:

Descargue datos hasta que se haga referencia a captcha e ingrese un bucle Descargue captcha y muéstrelo al usuario, inicieQEventLoop llamandoself.loop.exec_()SalidaQEventLoop llamandoloop.quit() en una ranura de subprocesos de trabajo que está conectada a través deself.line_edit.returnPressed.connect(self.worker.stop_waiting) en elmain_window clas Valide captcha y loop si falla la validación, de lo contrario, vuelva a intentar la última url que debería ser descargable ahora, luego continúe con la siguiente url

Lo que pasa

...véase más arriba..

ExitingQEventLoop no funciona. @self.loop.isRunning() devolucionesFalse después de llamar a suexit(). self.isRunning devolucionesTrue, como tal, el hilo no parecía morir en circunstancias extrañas. Aún así el hilo se detiene en laself.loop.exec_() line. Como tal, el hilo está atascado ejecutando el bucle de eventos a pesar de que el bucle de eventos me dice que ya no se está ejecutando.

La GUI responde al igual que las ranuras de la clase de subproceso de trabajo. Puedo ver el texto que se envía al subproceso de trabajo, el estado del bucle de eventos y el subproceso en sí, pero nada después de que se ejecute la línea mencionada anteriormente.

El código es un poco complicado, como tal agrego un poco de pseudocódigo-python-mix dejando de lado lo poco importante:

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_()

Respuestas a la pregunta(4)

Su respuesta a la pregunta