【问题标题】:update label in kivy parser app during infinite loop在无限循环期间更新kivy解析器应用程序中的标签
【发布时间】:2021-11-16 22:20:38
【问题描述】:

我正在为我的 selenium 解析器应用程序添加 gui,选择了 Kivy,但它不会更新标签文本。我找到了 StringProperty 解决方案和 Threading 来解决无限循环,但没有成功。 我需要这样的循环,因为应用程序应该不断地旋转搜索用户名的网站页面并说出它在哪个页面上找到。 请检查我的代码并纠正我,因为我错了:D 我试图为整个 kivy 应用程序的 while 循环和前台创建后台线程。 这是我得到的

import threading
import numpy as num

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

pages = num.arange(1, 70, 1)
firefox_options = webdriver.FirefoxOptions()
firefox_options.set_preference("permissions.default.image", 2)

global browsertab

class MyApp(App):
    position = StringProperty('Scan website')
    def __init__(self):
        super().__init__()
        self.label = Label(text = self.position)
        self.input_data = TextInput(hint_text = 'Enter username to serach for', multiline = False)
        self.input_data.bind(on_text_validate = self.on_enter)
        self.btn = Button(text = 'Scan')
        self.btn.bind(on_press = self.btn_pressed)
    def on_enter(self, *args):
        self.btn_pressed(self)
    def btn_pressed(self, *args):
        name = self.input_data.text
        background = threading.Thread(target=self.scanwebsite(name))
        background.start()
    def showpos(self, name, page):
        self.position = 'User ' + name + ' is currently on page #' + str(page)
    def build(self):
        box = BoxLayout(padding=20, orientation = 'vertical')
        box.add_widget(self.label)
        box.add_widget(self.input_data)
        box.add_widget(self.btn)
        return box

    def scanwebsite(self, name):
        with webdriver.Firefox(options=firefox_options) as driver:
            driver.get("https://website.com/")
            WebDriverWait(driver, 3)
            browsertab = driver.current_window_handle
            try:
                if driver.find_element(By.LINK_TEXT, "I ACCEPT"):
                    driver.find_element(By.LINK_TEXT, "I ACCEPT").click()
            except:
                pass
            
            while True:
                for page in pages:
                    url = "https://website.com/?page=" + str(page) 
                    driver.switch_to.window(browsertab)
                    driver.get(url)
                    WebDriverWait(driver, 2)
                    try:
                        if driver.find_element(By.LINK_TEXT, name.lower()):
                            self.showpos(name, page)
                            break
                    except:
                        pass
                    else:
                        continue
if __name__ == "__main__":
    foreground = threading.Thread(target=MyApp().run())
    foreground.start()
exit()

【问题讨论】:

  • 这是我的第一个 python 代码,所以请不要判断:)

标签: python selenium selenium-webdriver kivy


【解决方案1】:

您的代码存在一些问题:

  • 您不能在另一个线程中运行应用程序,它必须在main 线程中运行
  • Labeltext 设置为StringProperty,在python 代码中,只使用代码执行时StringProperty 的值。如果不添加更多代码来执行这些更新,就不会发生更新。
  • 代码background = threading.Thread(target=self.scanwebsite(name))实际上在当前线程中运行scanwebsite()方法,然后将其返回值(即None)分配给target参数。

如果您使用 kivy 语言来定义您的 GUI,您可以利用自动更新,例如更新使用 StringPropertyLabel。这是使用此方法的代码的修改版本:

import threading
from functools import partial

import numpy as num

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

pages = num.arange(1, 70, 1)
firefox_options = webdriver.FirefoxOptions()
firefox_options.set_preference("permissions.default.image", 2)

global browsertab

kv = '''
BoxLayout:
    padding: 20
    orientation: 'vertical'
    Label:
        text: app.position
    TextInput:
        id: input
        hint_text: 'Enter username to serach for'
        multiline: False
    Button:
        text: 'Scan'
        on_press: app.btn_pressed()
'''


class MyApp(App):
    position = StringProperty('Scan website')

    def on_enter(self, *args):
        self.btn_pressed(self)

    def btn_pressed(self, *args):
        name = self.root.ids.input.text  # get name by using id set in kv
        
        # use partial to set args for the scanwebsite() method
        # set daemon=True to kill this thread when the App quits
        background = threading.Thread(target=partial(self.scanwebsite, name), daemon=True)
        background.start()

    def showpos(self, name, page):
        self.position = 'User ' + name + ' is currently on page #' + str(page)

    def build(self):
        return Builder.load_string(kv)

    def scanwebsite(self, name):
        with webdriver.Firefox(options=firefox_options) as driver:
            driver.get("https://website.com/")
            WebDriverWait(driver, 3)
            browsertab = driver.current_window_handle
            try:
                if driver.find_element(By.LINK_TEXT, "I ACCEPT"):
                    driver.find_element(By.LINK_TEXT, "I ACCEPT").click()
            except:
                pass

            while True:
                for page in pages:
                    url = "https://website.com/?page=" + str(page)
                    driver.switch_to.window(browsertab)
                    driver.get(url)
                    WebDriverWait(driver, 2)
                    try:
                        if driver.find_element(By.LINK_TEXT, name.lower()):
                            self.showpos(name, page)
                            break
                    except:
                        pass
                    else:
                        continue


if __name__ == "__main__":
    MyApp().run()  # do not use a thread here

【讨论】:

    猜你喜欢
    • 2017-07-20
    • 1970-01-01
    • 2022-01-15
    • 2021-07-16
    • 2016-05-19
    • 2018-01-28
    • 1970-01-01
    • 2020-07-10
    相关资源
    最近更新 更多