Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 20, 2017 21:04:26

Metallikus
Зарегистрирован: 2014-11-26
Сообщения: 39
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt потоки и капча

Собрался, я, значится, свой говномесседжер для вконтактика запилить на pyqt. Само собой, все запросы к вк должны из отдельного потока идти, однако, вконтакт иногда запрашивает капчу, скотина эдакая. Кто-нибудь что-то подобное делал? С какой стороны к этой проблеме подойти вообще? Пока думаю для потока запросов использовать наследника QtCore.QThread с переопределённым run(), для работы с контактом - vk_api. Получается что-то такое:

 #!/usr/bin/python3
'''
Created on 20 янв. 2017 г.
@author: metallikus
'''
from PyQt5 import QtCore, QtWidgets, Qt
import vk_api
import datetime
import time
class MainWindow(QtWidgets.QMainWindow):
  def __init__(self, parent=None):
    QtWidgets.QMainWindow.__init__(self, parent)
    
    self.loginInput = QtWidgets.QLineEdit()
    self.passInput = QtWidgets.QLineEdit()
    self.urlInput = QtWidgets.QLineEdit()
    self.startButton = QtWidgets.QPushButton("spam!")
    
    self.setCentralWidget(QtWidgets.QWidget())
    self.centralWidget().setLayout(QtWidgets.QVBoxLayout())
    
    self.centralWidget().layout().addWidget(QtWidgets.QLabel("Логин:"))
    self.centralWidget().layout().addWidget(self.loginInput)
    self.centralWidget().layout().addWidget(QtWidgets.QLabel("Пароль:"))
    self.centralWidget().layout().addWidget(self.passInput)
    self.centralWidget().layout().addWidget(QtWidgets.QLabel("Url жертвы:"))
    self.centralWidget().layout().addWidget(self.urlInput)
    self.centralWidget().layout().addSpacerItem(QtWidgets.QSpacerItem(0,
                                                                      5,
                                                                      QtWidgets.QSizePolicy.Fixed,
                                                                      QtWidgets.QSizePolicy.Expanding))
    self.centralWidget().layout().addWidget(self.startButton)
    self.startButton.clicked.connect(self.startSpam)
    
  def startSpam(self):
    if (len(self.loginInput.text()) > 0 and
        len(self.passInput.text()) > 0 and
        len(self.urlInput.text()) > 0):
      self.msgSender = MsgSender(self.loginInput.text(),
                                 self.passInput.text(),
                                 self.urlInput.text())
      self.msgSender.start()
    else:
      QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning,
                            "egg",
                            "Заполните все поля, пожалуйста!",
                            QtWidgets.QMessageBox.Ok, self).show()
      
class CaptchaWindow(QtWidgets.QWidget):
  def __init__(self, parent=None):
    QtWidgets.QWidget.__init__(self, parent)
    self.setLayout(QtWidgets.QVBoxLayout())
    self.layout().addWidget(QtWidgets.QLabel("Капча вылезла!"))
    
    
class MsgSender(QtCore.QThread):
    printTxt = QtCore.pyqtSignal(str) #сигнал для передачи текста родителю
    
    def __init__(self, login=None, password=None, url=None, parent=None):
      QtCore.QThread.__init__(self, parent)
      self.login = login
      self.password = password
      self.url = url
      
    def captchaHandler(self, captcha):
      key = """
      Как-то запросить ввод капчи из гуи-потока, но, блин, как, мать его?
      """
      print("Капча, блин")
      return captcha.try_again(key)
    
    def run(self):
      vk1 = vk_api.VkApi(self.login, self.password, captcha_handler=self.captchaHandler)
      vk1.authorization()
      screenName = self.url.strip().split("/")[-1]
      userId = vk1.method("users.get", {"user_ids": screenName})[0]["id"]
      while True:
        vk1.method("messages.send",{"user_id": userId,
                                         "message":datetime.datetime.now(),
                                         "random_id":int(datetime.datetime.now().timestamp())})
    
    
def run():
  import sys
  app = Qt.QApplication(sys.argv)
  window = MainWindow()
  window.setWindowTitle("Заголовок")
  
  window.show()
  sys.exit(app.exec_())
  
if __name__ == "__main__":
  run()
На месте “Как-то запросить ввод капчи из гуи-потока…” нужно какой-то mutex или ещё чего использовать… Вот хотелось бы узнать что именно? Или вообще QtCore.QThread тут не прокатит? А что тогда?

Офлайн

#2 Янв. 22, 2017 01:18:48

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

PyQt потоки и капча

Metallikus
А что тебе мешает в потоке отлавливать запрос капчи, извлекать картинку с капчой, передавать ее с помощью сигнала в главный поток, чтобы там попросить пользователя ввести код?
В общем тут все решает слотами и сигналами без каких либо проблем)

Офлайн

#3 Янв. 22, 2017 14:26:18

Metallikus
Зарегистрирован: 2014-11-26
Сообщения: 39
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt потоки и капча

А назад из gui-потока как вбитый код передать? Да и поток должен стоять и ждать, пока капчу не введут.

Офлайн

#4 Янв. 22, 2017 17:20:10

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

PyQt потоки и капча

Metallikus
Слоты и сигналы тебе в помощь. Я не представляю как можно кодить на qt и не знать об этом.

Офлайн

#5 Янв. 23, 2017 09:38:00

Metallikus
Зарегистрирован: 2014-11-26
Сообщения: 39
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt потоки и капча

Но ведь если из гуя обратиться к слоту Qthread, то гуй повесится же. Обновлённый captchaHandler:

     def captchaHandler(self, captcha):
      captchaFile = open(os.path.join(self.tmpFilesPath, "captcha.jpg"), "wb")
      captchaFile.write(captcha.get_image())
      captchaFile.close()
      self.captchaNeeded.emit() #Передали сигнал в гуй, тот показал окошко, юзер вбил туда капчу
      
      "Как-то поставить поток на паузу, что ли..."
      
      "Как-то снять поток с паузы, когда капча вбита"
      
      key = "Вбитая юзером капча"
      print("Капча, блин")
      
      return captcha.try_again(key)

Офлайн

#6 Янв. 23, 2017 10:45:54

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt потоки и капча

Парюсь похожим вопросом. Нашёл такую штуку, но не разобрался, может поможет Вам:
https://pythonworld.ru/moduli/modul-subprocess.html - фишка в timeout
Можно поизучать код программы тетрис (https://pythonworld.ru/gui/pyqt5-tetris.html ) - в коде есть функция паузы.
Есть ещё модуль time, но думаю, он не подходит.

Отредактировано Kyrym (Янв. 23, 2017 10:46:06)

Офлайн

#7 Янв. 23, 2017 10:57:55

Metallikus
Зарегистрирован: 2014-11-26
Сообщения: 39
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt потоки и капча

В общем, я хз, так или не так делаются подобные вещи, но пока работает:
В __init__ спам-потока:

 self.mutex = Qt.QMutex() #хз зачем эта штука, но без неё не работает
 self.captchaInputed = Qt.QWaitCondition() #паузатор
Обработчик капчи:
     def captchaHandler(self, captcha):
      captchaFile = open("captcha.jpg", "wb")
      captchaFile.write(captcha.get_image())
      captchaFile.close()
      self.captchaNeeded.emit() #Передали сигнал в гуй, тот показал окошко, юзер вбил туда капчу
      
      self.captchaInputed.wait(self.mutex) #ждём, пока кто-нить не сделает captchaInputed.wake-сколько-нибудь
      
      #продолжаем после вызова captchaInputed.wakeAll() из гуя
      key = self.key
      
      return captcha.try_again(key)
Ну и run() спам-потока начинается с этого:
 def run(self):
      self.mutex.lock()
Это нормальное решение?

Отредактировано Metallikus (Янв. 23, 2017 11:15:13)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version