updating tkinter label while another loop runs

Viewed 70
import tkinter as tk
from tkinter import messagebox
import re,sys
from urllib.parse import urlparse
import requests,time
from bs4 import BeautifulSoup
class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Quotes Scraper v1")
        self.geometry("400x250")
        button = tk.Button(self, text="Collect Links",bd=3, 
            activebackground="grey90",command=self.start_collecting)
        button.place(x=130,y=120)

    def start_collecting(self):
        url = "http://quotes.toscrape.com/"
        res=requests.get(url)
        is res.status_code!=200:
            sys.exit('Check Internet')
        self.clean_screen_plus()
        quotes = []
        while True:
            soup = BeautifulSoup(res.text,'lxml')
            self.update_status()
            quotes+=[i.span.text.strip() for i in soup.findAll('div',{'class':'quote'})]
            try:
                next_page = 'http://quotes.toscrape.com/'+ soup.find('li',{'class':'next'}).a['href']
                time.sleep(5)
                res = requests.get(next_page)
            except AttributeError:
                break
        self.destroy()

    def clean_screen_plus(self,):
        for widget in self.winfo_children():
            widget.destroy()
        self.geometry("300x100")
        self.resizable(False, False)
        self.status = tk.Label(self, text="Collecting")
        self.status.grid()
        self.update_idletasks()

    def update_status(self):

        current_status = self.status["text"]
        if current_status.endswith("..."): 
            current_status = "Collecting"

        else: 
            current_status += "."

        # Update the message
        self.status["text"] = current_status
        self.update_idletasks()
        self.after(1000, update_status) #updates every 1 sec
        print(current_status)
App().mainloop()

Hello, I have this code, How can I keep upgrading the tkinter Label while the while loop is running, I.e I want the status to keep changing every second to update status regardless where I am at in the while loop.

expected output on the tkinter is Collecting.\n {len(quotes)} then Collecting.. {len(quotes)} ... until the while loop finishes then just self.destroy()

1 Answers

You should use a thread to scrape the page else it will block it.

This code worked for me,(Although it need to waste some time,I have add annotataion in my code):

import tkinter as tk
from tkinter import messagebox
import re,sys
from urllib.parse import urlparse
import requests,time
from bs4 import BeautifulSoup
import threading

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Quotes Scraper v1")
        self.geometry("400x250")
        button = tk.Button(self, text="Collect Links",bd=3,
            activebackground="grey90",command=self.start_thread) # start a thread instead of starting scrap the page.
        button.place(x=130,y=120)

    def start_thread(self):
        threading.Thread(target=self.start_collecting).start() # create a thread to scrap a page in the background

    def start_collecting(self): # this is your work.
        url = "http://quotes.toscrape.com/"
        res = requests.get(url)
        if res.status_code != 200:
            sys.exit('Check Internet')

        self.clean_screen_plus()
        quotes = []
        while True:
            soup = BeautifulSoup(res.text, 'lxml')
            self.update_status()
            quotes += [i.span.text.strip() for i in soup.findAll('div', {'class': 'quote'})]
            try:
                next_page = 'http://quotes.toscrape.com/' + soup.find('li', {'class': 'next'}).a['href']
                time.sleep(5)
                res = requests.get(next_page)
            except AttributeError:
                break
        self.destroy()

    def clean_screen_plus(self):
        for widget in self.winfo_children():
            widget.destroy()
        self.geometry("300x100")
        self.resizable(False, False)
        self.status = tk.Label(self, text="Collecting")
        self.status.grid()

    def update_status(self):

        current_status = self.status["text"]
        if current_status.endswith("..."):
            current_status = "Collecting"

        else:
            current_status += "."

        # Update the message
        self.status["text"] = current_status
        self.update_idletasks()
        self.after(1000, self.update_status) #updates every 1 sec
        print(current_status)
App().mainloop()
Related