Освежающий BeautifulSoup в Ткинтере - PullRequest
0 голосов
/ 02 января 2019

Попытка запустить мой скрипт в цикле, чтобы информация, полученная с веб-страницы с помощью BeautifulSoup, обновлялась каждые X секунд.Это должно происходить во время работы Tkinter и отображения информации.

В настоящее время я обнаруживаю, что вообще не могу зациклить скрипт.Это мой сценарий

    import tkinter as tk
    root = tk=Tk()
    root.title('Title')
    from bs4 import BeautifulSoup, Navigable String
    import requests
    import time

    page = requests.get("http://yourpage.com")
    #get info from page

    canvas.create_text(100, 100 text="text")
    #display info

    root.after(100,update)
    root.mainloop()

Я пытался вставить while True:, но у меня ничего не получилось.Я думаю, что это может быть до root.mainloop(), но я не знаю, как обойти это, потому что без этого GUI не открывается.

EDIT

This is my code and it works where it will refresh, however, I don't think this is the proper way of doing it:

import tkinter as tk
root = tk.Tk()
root.title('title')
screen = tk.Canvas(root, width=400, height=600, background='gray15')
screen.grid()
root.iconbitmap(r'C:\\path\to\file.ico')
while True:

    from bs4 import BeautifulSoup, NavigableString
    import requests
    import time
    #SWDL Current
    page = requests.get("https://yourwebpage.com")
    page = requests.get("https://yourwebpage.com/page", cookies=page.cookies)
    soup = BeautifulSoup(page.content, 'html.parser')
    soup.find_all('td')
    yourdata = soup.find_all('td')[12].get_text()

    vara = yourdata[0:1]
    varb = yourdata[1:2]
    varc = yourdata[2:3]
    var1 = int(vara)
    var2 = int(varb)
    var3 = int(varc)

    offsets = (
        (0, 0, 1, 0),  # top
        (1, 0, 1, 1),  # upper right
        (1, 1, 1, 2),  # lower right
        (0, 2, 1, 2),  # bottom
        (0, 1, 0, 2),  # lower left
        (0, 0, 0, 1),  # upper left
        (0, 1, 1, 1),  # middle
    )
    # Segments used for each digit; 0, 1 = off, on.
    digits = (
        (1, 1, 1, 1, 1, 1, 0),  # 0
        (0, 1, 1, 0, 0, 0, 0),  # 1
        (1, 1, 0, 1, 1, 0, 1),  # 2
        (1, 1, 1, 1, 0, 0, 1),  # 3
        (0, 1, 1, 0, 0, 1, 1),  # 4
        (1, 0, 1, 1, 0, 1, 1),  # 5
        (1, 0, 1, 1, 1, 1, 1),  # 6
        (1, 1, 1, 0, 0, 0, 0),  # 7
        (1, 1, 1, 1, 1, 1, 1),  # 8
        (1, 1, 1, 1, 0, 1, 1),  # 9
    )

    if yourdata == 'x':
        class Digit:
            def __init__(self, canvas, x=10, y=10, length=20, width=4):
                self.canvas = canvas
                l = length
                self.segs = []
                canvas.create_line(250, 53, 270, 8, width=3, fill="snow")
                canvas.create_oval(250, 10, 255, 15, outline="snow", fill="snow", width=0)
                canvas.create_oval(265, 46, 270, 51, outline="snow", fill="snow", width=0)
                canvas.create_text(70, 30, text='info', font=('OCR A Extended', '18'), fill='snow')
                for x0, y0, x1, y1 in offsets:
                    self.segs.append(canvas.create_line(
                        x + x0*l, y + y0*l, x + x1*l, y + y1*l,
                        width=width, state = 'hidden', fill='snow'))
            def show(self, num):
                for iid, on in zip(self.segs, digits[num]):
                    self.canvas.itemconfigure(iid, state = 'normal' if on else 'hidden')

        dig = Digit(screen, 160, 10) ##
        dig1 = Digit(screen, 190, 10) ##
        dig2 = Digit(screen, 220, 10) ##
        n = 0
        def update():
            global n
            dig.show(var1)
            dig1.show(var2)
            dig2.show(var3)
            n = (n+1) % 10
            root.after(1000, update)
    else:
        class Digit:
            def __init__(self, canvas, x=10, y=10, length=20, width=4):
                self.canvas = canvas
                l = length
                self.segs = []
                canvas.create_line(220, 53, 240, 8, width=3, fill="snow")
                canvas.create_oval(220, 15, 225, 10, outline="snow", fill="snow", width=0)
                canvas.create_oval(235, 46, 240, 51, outline="snow", fill="snow", width=0)
                canvas.create_text(70, 30, text='info', font=('OCR A Extended', '18'), fill='snow')
                for x0, y0, x1, y1 in offsets:
                    self.segs.append(canvas.create_line(
                        x + x0*l, y + y0*l, x + x1*l, y + y1*l,
                        width=width, state = 'hidden', fill='ghost white'))
            def show(self, num):
                for iid, on in zip(self.segs, digits[num]):
                    self.canvas.itemconfigure(iid, state = 'normal' if on else 'hidden')

        dig = Digit(screen, 160, 10) ##
        dig1 = Digit(screen, 190, 10) ##
        n = 0
        def update():
            global n
            dig.show(var1)
            dig1.show(var2) ## Control what you want to show here , eg (n+1)%10
            n = (n+1) % 10
            root.after(1000, update)
    root.after(1000, update)
    root.update_idletasks()
    root.update()

Или, если есть способ обновить только Beautifulsoup, который тоже может работать.

Любая помощь приветствуется

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Короткий ответ, боюсь, у меня мало времени

В подобных случаях, когда вам нужно запустить два цикла одновременно, встроенный в Python модуль потоков - ваш лучший друг.

Возьмем простой пример:

Распечатать счетчик, пока открыто окно Tkinter

import tkinter as tk
import time
import threading


def gui():
    root = tk.Tk()
    root.mainloop()


count = 0
def counter():
    global count
    while True:
        count += 1
        time.sleep(1)
        print count


threads = []
countbot = threading.Thread(target=counter)
threads.append(countbot)
countbot.start()

gui()

Очевидно, вы можете заменить счетчик на что угодно.

Это должно направить вас на правильный путь.

Удачи!

Edit:

Я не уверен, насколько вы знакомы с потоками; Чтобы быстро объяснить, что здесь происходит:

Ваш код застревает в первом цикле и останется в цикле навсегда, и не попадет ни в какой другой код. Потоки запускают несколько частей вашего сценария одновременно, поэтому цикл может выполняться в фоновом режиме, в то время как остальная часть кода продолжается.

0 голосов
/ 02 января 2019

Ваш пример немного скудный и не тот, который мы можем проверить.Однако простое решение состоит в том, чтобы создать функцию, которую можно вызывать в любой требуемый интервал времени.

Вот базовый пример:

def update_canvas():
    canvas.delete("all")
    canvas.create_text(100, 100, text=data_gathered)
    root.after(100, update_canvas)

update_canvas()

Используя after() в функции, которую выможно избежать блокировки основного цикла и поддерживать постоянное обновление.

Редактировать:

Ваш полный код немного сложно протестировать из-за этой строки:

yourdata = soup.find_all('td')[12].get_text()

Не зная URL-адреса, предназначенного для этого, я никак не могу получить результаты.Тем не менее, я немного переработал ваш код, чтобы он лучше работал с mainloop.Думаю, что в какой-то момент все это должно быть преобразовано в ООП, чтобы вы могли избежать глобального.

import tkinter as tk
from bs4 import BeautifulSoup
import requests


root = tk.Tk()
root.title('title')
screen = tk.Canvas(root, width=400, height=600, background='gray15')
screen.grid()

url_to_request = "https://google.com"
page = requests.get(url_to_request)
soup = BeautifulSoup(page.content, 'html.parser')
soup.find_all('td')
yourdata = soup.find_all('td')[12].get_text()
var1 = int(yourdata[0:1])
var2 = int(yourdata[1:2])
var3 = int(yourdata[2:3])

offsets = (
    (0, 0, 1, 0),  # top
    (1, 0, 1, 1),  # upper right
    (1, 1, 1, 2),  # lower right
    (0, 2, 1, 2),  # bottom
    (0, 1, 0, 2),  # lower left
    (0, 0, 0, 1),  # upper left
    (0, 1, 1, 1),  # middle
    )

digits = (
    (1, 1, 1, 1, 1, 1, 0),  # 0
    (0, 1, 1, 0, 0, 0, 0),  # 1
    (1, 1, 0, 1, 1, 0, 1),  # 2
    (1, 1, 1, 1, 0, 0, 1),  # 3
    (0, 1, 1, 0, 0, 1, 1),  # 4
    (1, 0, 1, 1, 0, 1, 1),  # 5
    (1, 0, 1, 1, 1, 1, 1),  # 6
    (1, 1, 1, 0, 0, 0, 0),  # 7
    (1, 1, 1, 1, 1, 1, 1),  # 8
    (1, 1, 1, 1, 0, 1, 1),  # 9
    )


def update(if_else_var):
    global dig, dig1, dig2, n
    soup = BeautifulSoup(requests.get(url_to_request).content, 'html.parser')
    yourdata = soup.find_all('td')[12].get_text()
    var1 = int(yourdata[0:1])
    var2 = int(yourdata[1:2])
    var3 = int(yourdata[2:3])
    dig.show(var1)
    dig1.show(var2)
    if if_else_var:
        dig2.show(var3)
    n = (n+1) % 10
    root.after(1000, update, if_else_var)

if yourdata == 'x':
    global dig, dig1, dig2, n

    class Digit:
        def __init__(self, canvas, x=10, y=10, length=20, width=4):
            self.canvas = canvas
            canvas.delete('all')
            l = length
            self.segs = []
            canvas.create_line(250, 53, 270, 8, width=3, fill="snow")
            canvas.create_oval(250, 10, 255, 15, outline="snow", fill="snow", width=0)
            canvas.create_oval(265, 46, 270, 51, outline="snow", fill="snow", width=0)
            canvas.create_text(70, 30, text='info', font=('OCR A Extended', '18'), fill='snow')
            for x0, y0, x1, y1 in offsets:
                self.segs.append(canvas.create_line(x + x0*l, y + y0*l, x + x1*l, y + y1*l,
                                                    width=width, state='hidden', fill='snow'))

        def show(self, num):
            for iid, on in zip(self.segs, digits[num]):
                self.canvas.itemconfigure(iid, state='normal' if on else 'hidden')

    dig = Digit(screen, 160, 10)
    dig1 = Digit(screen, 190, 10)
    dig2 = Digit(screen, 220, 10)
    n = 0
    update(True)
else:

    class Digit:
        def __init__(self, canvas, x=10, y=10, length=20, width=4):
            self.canvas = canvas
            canvas.delete('all')
            l = length
            self.segs = []
            canvas.create_line(220, 53, 240, 8, width=3, fill="snow")
            canvas.create_oval(220, 15, 225, 10, outline="snow", fill="snow", width=0)
            canvas.create_oval(235, 46, 240, 51, outline="snow", fill="snow", width=0)
            canvas.create_text(70, 30, text='info', font=('OCR A Extended', '18'), fill='snow')
            for x0, y0, x1, y1 in offsets:
                self.segs.append(canvas.create_line(
                    x + x0*l, y + y0*l, x + x1*l, y + y1*l,
                    width=width, state='hidden', fill='ghost white'))

        def show(self, num):
            for iid, on in zip(self.segs, digits[num]):
                self.canvas.itemconfigure(iid, state='normal' if on else 'hidden')

    dig = Digit(screen, 160, 10)
    dig1 = Digit(screen, 190, 10)
    n = 0
    update(False)

root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...