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)内置Pythonthreading
library(参考Python文档)在后台运行耗时的搜索任务,这样它就不会阻塞tkinter
main循环;2) 使用StringVar
()作为桥梁,将搜索结果从后台任务转移到主任务,并在更新StringVar
时设置处理程序;3) 使用文本
小部件替换控制台输出。希望这有帮助。