Python 采用Tkinter接口的自适应算法

Python 采用Tkinter接口的自适应算法,python,tkinter,Python,Tkinter,开发了一种非常简单的算法,可以根据网站上的搜索词过滤答案: 算法: from bs4 import BeautifulSoup import requests import time while True: buscar = input('\033[6;32;1mDigite o Termo de Buscar:\033[m ') print('Buscando Repostas ....') data = [{"operationName": "SearchQue

开发了一种非常简单的算法,可以根据网站上的搜索词过滤答案:

算法:

from bs4 import BeautifulSoup
import requests
import time


while True:

    buscar = input('\033[6;32;1mDigite o Termo de Buscar:\033[m ')
    print('Buscando Repostas ....')
    data = [{"operationName": "SearchQuery", "variables": {"query":buscar, "after": None, "first": 90},
         "query": "query SearchQuery($query: String!, $first: Int!, $after: ID) {\n  questionSearch(query: $query, first: $first, after: $after) {\n    count\n    edges {\n      node {\n        id\n        databaseId\n        author {\n          id\n          databaseId\n          isDeleted\n          nick\n          avatar {\n            thumbnailUrl\n            __typename\n          }\n          rank {\n            name\n            __typename\n          }\n          __typename\n        }\n        content\n        answers {\n          nodes {\n            thanksCount\n            ratesCount\n            rating\n            __typename\n          }\n          hasVerified\n          __typename\n        }\n        __typename\n      }\n      highlight {\n        contentFragments\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n}\n"}]
    r = requests.post("https://brainly.com.br/graphql/pt", json=data).json()

    p=[]
    for item in r[0]['data']['questionSearch']['edges']:
        rst=(f"https://brainly.com.br/tarefa/{item['node']['databaseId']}")
        p.append(rst)


    for ele in p:
        r = requests.get(ele).text
        soup = BeautifulSoup(r,'html.parser')

        for n in soup.find_all('div', attrs={'class': 'brn-content-image'}):
            ty = (n.find('h1').text)
            print("\033[37;31;1m[Title]:\033[m {0}".format(ty))

            for t in soup.find_all('div', attrs={'class': 'sg-text js-answer-content brn-rich-content'}):
                u=(t.text)
                print("\033[6;33;1mResposta: \n \033[m{0}".format(u)) 
为了处理这个算法,我在
Tkinter
中制作了一个非常基本的界面:

from tkinter import *
def resposta():
    b['text'] = '  Aguarde! , Procurando Respostas ....  '
    b['fg'] = 'green'
    b['bg'] = 'white'
    b['font'] = ('Verdana','9','bold')

i = Tk()

i.title('Respostas Brainly')

i.geometry('800x600')
t = Label(i, text = 'Buscador de Respostas Brainly : ',fg = 'red', font = ('Arial','13','bold'),padx=0, pady=10)
t.pack()
e = Entry(i)
b =Button(i, text = '   Clique   ',font = ('Verdana','10','bold'), fg = 'grey', command = resposta,bg = 'black')
e.pack()
'\n'
b.pack()
i.mainloop()
但我怀疑我是如何让我的算法与界面交互的:

示例:我在字段中键入一些搜索词,它会触发算法并在
Tkinter
界面屏幕上打印答案


与控制台中相同:

实际上,您想要执行的操作的逻辑与这个小示例相同。 在这个例子中,我有一个GUI界面,它只运行一个循环。在GUI的底部有一个绑定到本地字典的条目。当用户输入一个单词并单击搜索按钮时,如果找到该单词,则返回结果(在本例中,返回结果的唯一关键字是workd:“关键字”)。使用
线程
模块将循环放置在
线程
中,以便异步运行,并且不要阻塞tkinter主循环

在你的情况下,如果我理解正确,你只需要一个输入(让用户输入研究的关键字)和一个运行按钮就可以开始抓取
网站
,刮取网站的函数必须位于
线程中,因为它使用无限循环,否则会阻塞tkinter循环,从而阻塞GUI

import tkinter as tk
import threading as th
import time



class App:

    def __init__(self):
        self.root = tk.Tk()

        self.run = True
        self.search_dict = {'keyword': 'keyword value'}
        self.counter = 0

    def build(self):
        self.counter_label = tk.Label(text=self.counter)
        self.counter_label.pack()



        self.keyword_variable = tk.StringVar()
        self.entry = tk.Entry(textvariable=self.keyword_variable)
        self.entry.pack()

        self.search_button = tk.Button(text='search', command=self.run_counter)
        self.search_button.pack()

        self.stop_button = tk.Button(text='stop', command=self.stop_counter)
        self.stop_button.pack()

    def start_counter(self):
        while self.run:
            current__keyword = self.keyword_variable.get().strip()
            if current__keyword in self.search_dict:
                result = self.search_dict[current__keyword]
            else:
                result = 'Keyword is empy or not in the dictionary'
            self.counter += 1
            self.counter_label.configure(text='Keyword found: ' + result + ', Search process number: ' + str(self.counter))
            time.sleep(1)

    def run_counter(self):
        self.my_thread = th.Thread(target=self.start_counter) # create new thread that runs the self.start_counter() function
        self.my_thread.start() # start the threading

    def stop_counter(self):
        self.counter_label.configure(text="counter stopped")
        self.run = False # set the variable to false so that the while loop inside the threading stops
        self.my_thread.join() # this destoy the created threading

    def start_loop(self):
        self.root.mainloop() # starts the tkinter mainloop

app = App()
app.build()

app.start_loop()

您可以使用
Text
小部件保存搜索结果。将搜索逻辑移到
resposta()
函数中:

from tkinter import *
import requests
from threading import Thread
from bs4 import BeautifulSoup

def append_text(txt):
  result_log.insert(END, txt)
  result_log.see(END)

def resposta(buscar, max_results=10):
  data = [{
    "operationName": "SearchQuery",
    "variables": {
      "query": buscar,
      "after": None, 
      "first": 90
    },
    "query": """
      query SearchQuery($query: String!, $first: Int!, $after: ID) {
        questionSearch(query: $query, first: $first, after: $after) {
          count
          edges {
            node {
              id
              databaseId
              author {
                id
                databaseId
                isDeleted
                nick
                avatar {
                  thumbnailUrl
                  __typename
                }
                rank {
                  name
                  __typename
                }
                __typename
              }
              content
              answers {
                nodes {
                  thanksCount
                  ratesCount
                  rating
                  __typename
                }
                hasVerified
                __typename
              }
              __typename
            }
            highlight {
              contentFragments
              __typename
            }
            __typename
          }
          __typename
        }
      }
    """
  }]
  resp = requests.post('https://brainly.com.br/graphql/pt', json=data).json()
  cnt = 0
  for item in resp[0]['data']['questionSearch']['edges']:
    url = f"https://brainly.com.br/tarefa/{item['node']['databaseId']}"
    r = requests.get(url).content
    soup = BeautifulSoup(r, 'html.parser')
    for n in soup.find_all('div', attrs={'class': 'brn-content-image'}):
      ty = n.find('h1').text
      result.set(f'[Title #{cnt+1}]: {ty}\n')
      for t in soup.find_all('div', attrs={'class': 'sg-text js-answer-content brn-rich-content'}):
        result.set(f'[Resposta]: {t.text}\n')
    cnt += 1
    if cnt == max_results: break
  # thread task completed, reset thread ID
  global tid
  tid = None

def start_search():
  global tid
  # start a new thread if no thread task is running
  if tid is None:
    result_log.delete(1.0, END) # clear last result log
    tid = Thread(target=resposta, args=(e.get(),), daemon=1)
    tid.start()


tid = None   # hold the thread ID

root = Tk()
root.title('Respostas Brainly')
root.geometry('800x600')

# use for transfer result from running thread
result = StringVar()
result.trace('w', lambda *a: append_text(result.get()))

frm = Frame(root)
frm.pack(fill=X)

Label(frm, text='Buscador de Respostas Brainly:', fg='red', font=('Arial','13','bold'), padx=0, pady=10).pack(side=LEFT)

e = Entry(frm)
e.pack(side=LEFT)

Button(frm, text='Clique', font=('Verdana','10','bold'), fg='grey', command=start_search, bg='black').pack(side=LEFT)

frm = Frame(root)
frm.pack(fill=BOTH, expand=1)

# use a Text box to hold the search result
result_log = Text(frm)
result_log.pack(side=LEFT, fill=BOTH, expand=1)

sb = Scrollbar(frm, orient=VERTICAL, command=result_log.yview)
sb.pack(side=RIGHT, fill=Y)

result_log.config(yscrollcommand=sb.set)

root.mainloop()

不,你的例子我需要一些东西来发送条目,在我点击一个显示结果的按钮后,我可以用我的代码片段来解释。@Soares我已经编辑了一点这个例子,也许现在你可以更好地理解它如何适合你的解决方案。这很可能不起作用。tkinter的大多数版本都不是线程安全的,因此在主线程以外的任何地方访问小部件方法都有可能以不可预知的方式中断。您是否有任何替代解决方案?如果不鼓励风险导入,请小心!此外,您应该使用
.content
,而不是
.text
,将请求的结果传递给BeautifulSoup。解决了我的问题,是否有关于您在该代码中所做操作的文档?如果你离开链接。与你的代码相比,我的代码使用了:1)内置Python
threading
library(参考Python文档)在后台运行耗时的搜索任务,这样它就不会阻塞
tkinter
main循环;2) 使用
StringVar
()作为桥梁,将搜索结果从后台任务转移到主任务,并在更新
StringVar
时设置处理程序;3) 使用
文本
小部件替换控制台输出。希望这有帮助。