Reputation: 13
I am tying to add gui for my selenium parser app, chose Kivy, but it doesnt update label text. I found StringProperty solution and Threading to workaround an infinite loop, but yet unsuccessfully. I need such loop cause app should constantly rotate the site pages searching for username and saying what page was it found at. Please, check my code and correct me cause I'm def wrong :D I tried to make backround thread for the while loop and foreground for a whole kivy app. Here's what I got
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()
Upvotes: 0
Views: 201
Reputation: 38992
Some problems with your code:
main
threadtext
of a Label
to a StringProperty
, in python code, just uses the value of the StringProperty
at the time that code gets executed. No updates will happen without adding more code to do those updates.background = threading.Thread(target=self.scanwebsite(name))
actually runs the scanwebsite()
method in the current thread and then assigns its return (which is None
) to the target
argument.If you use the kivy language to define your GUI, you can take advantage of automatic updates, like updating a Label
that uses StringProperty
. Here is a modified version of your code that uses this approach:
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
Upvotes: 0