Ich wollte ein Tool vom Typ GUI, das Seiten mit demselben Such-Tag auf EC-Websites und Websites für Arbeitspostings gleichzeitig öffnet.
・ (Die json-Klasse ist eine Verbesserung der zuvor erstellten und hat sie zu einem gemeinsamen Teil gemacht.) ・ Implementierte die Handling-Klasse des Tkinter-Kombinationsfelds und machte es zu einem gemeinsamen Teil
・ Windows10 ・ Python 3.7.0 ・ Entwicklung ist Pycharm
Die GUI sieht so aus.
webSiteDetails.json
{
"WebSiteA": {
"OnlyOpenPage": true,
"PageSet": [
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com"
]
},
"WebSiteB": {
"OnlyOpenPage": true,
"PageSet": [
"http://foobar.com",
"http://foobar.com"
]
},
"WebSiteC": {
"OnlyOpenPage": true,
"PageSet": [
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com"
]
},
"WebSiteD": {
"OnlyOpenPage": true,
"PageSet": [
"http://foobar.com",
"http://foobar.com",
"http://foobar.com",
"http://foobar.com"
]
},
"WebSiteE": {
"OnlyOpenPage": true,
"PageSet": [
"http://foobar.com",
"http://foobar.com",
"http://foobar.com"
]
}
}
Die Eigenschaft "Nur OpenPage" wurde hinzugefügt Bei der zukünftigen Implementierung der Scraping-Funktion Öffne es einfach Zuschuss für Schrottverarbeitung, Ich wollte einen Unterschied machen.
JsonHandler.py
import json
class JsonHandler:
def __init__(self, jsonPath):
#Json-Datei lesen
self.file = open(jsonPath, 'r', encoding="utf-8_sig")
self.jsonData = json.load(self.file)
#Holen Sie sich JSON-Daten für das primäre Nest
def getParam_OneNest(self, args):
return self.jsonData[args]
#Holen Sie sich die JSON-Datenliste des primären Nestes
def getAll_OneNest(self):
# list = []
# for d in self.jsonData.keys():
# list.append(d)
list = [d for d in self.jsonData.keys()]
return list
#Holen Sie sich JSON-Daten für die sekundäre Verschachtelung
def getParam_TwoNest(self, args1, args2):
return self.jsonData[args1][args2]
def __del__(self):
#Datei schließen
self.file.close()
Ich habe die zuvor erstellte (*) ein wenig geändert. Weil es notwendig war, nur die Daten des primären Nestes auf einmal zu erfassen. [※:https://qiita.com/dede-20191130/items/65b0f4c3c2b5c7f97546]
list = [d for d in self.jsonData.keys()]
Dies ist ein Listeneinschlussformat.
TkHandler_Combo_1.py
import tkinter as tk
import tkinter.ttk as ttk
class TkHandler_Combo_1:
"""Gemeinsame Teile der GUI. Erstellen Sie ein Kombinationsfeld"""
def __init__(self, rootTitle='Titel', rootGeometry='640x480'):
#Erstellen eines Stammrahmens
self.root = tk.Tk()
self.root.title(rootTitle)
#Stammfenstergröße als Argumentwert
self.root.geometry(rootGeometry)
#Schließen Sie die Ereigniseinstellungen
self.root.protocol("WM_DELETE_WINDOW", self.onClosing)
self.frame = None
self.label = None
self.combo = None
self.button = None
self.isDestroyed = False
def createFrame(self):
#Rahmen erstellen
self.frame = ttk.Frame(self.root, width=self.root.winfo_width() - 20, height=self.root.winfo_height() - 20,
padding=10)
self.frame.pack()
def createLabel(self, myText="Bitte auswählen"):
#Etikett erstellen
self.label = ttk.Label(self.frame, text=myText, padding=(5, 5))
self.label.pack()
def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
#Breiteneinstellung
myWidth = myWidth or self.frame.winfo_width() - 20
#Kombinationsfeld erstellen
self.combo = ttk.Combobox(self.frame, width=myWidth, state=myState)
self.combo["values"] = myValue
#Standardwert(index=0)Einstellen
self.combo.current(0)
#Platzierung des Kombinationsfeldes
self.combo.pack(padx=5, pady=5, fill=tk.X)
def createButton(self, myText="Lauf", myFunc=None):
"""Nehmen Sie eine Funktion als Argument"""
#Funktionseinstellungen
myFunc = myFunc or (lambda: self.dummy())
#Eine Schaltfläche erstellen
self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
#* ↑↑ Zuerst wurde es so implementiert
# if myFunc:
# self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
# else:
# self.button = tk.Button(text=myText, command=lambda: self.dummy())
#Platzierung der Tasten
self.button.pack(padx=5, pady=5, )
def dummy(self, arg=''):
pass
def mainLoop(self):
self.root.mainloop()
def onClosing(self):
self.root.destroy()
self.isDestroyed = True
def __del__(self):
if not self.isDestroyed:
self.root.destroy()
#Schließen Sie die Ereigniseinstellungen
self.root.protocol("WM_DELETE_WINDOW", self.onClosing)
Eine Syntax, die eine Methode festlegt, die aufgerufen wird, wenn das Fenster geschlossen wird, ohne die Schaltfläche Ausführen zu drücken. Löschen Sie den Rahmen, bevor Sie ihn mit onClosing schließen Verhindert Fehler, wenn der Destruktor (\ __ del__ Funktion) funktioniert.
def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
#Breiteneinstellung
myWidth = myWidth or self.frame.winfo_width() - 20
Wenn für myWidth ein Argument angegeben wird, hat es weiterhin diesen Wert. Wenn das Standardargument None übrig bleibt, wird ein Wert eingegeben, der 20 kleiner als der Breitenwert des Frames ist.
Ich habe auf diesen Artikel verwiesen, um zu erfahren, wie oder. https://blog.pyq.jp/entry/python_kaiketsu_181016
Der Grund, warum ich "self.frame.winfo_width () -20" nicht direkt in das Standardargument eingefügt habe, ist Es scheint, dass Sie die Feldmitglieder Ihrer eigenen Klasse nicht als Argumente verwenden können. Wenn jemand weiß, dass es einen möglichen Weg gibt, lass es mich wissen.
def createButton(self, myText="Lauf", myFunc=None):
"""Nehmen Sie eine Funktion als Argument"""
#Funktionseinstellungen
myFunc = myFunc or (lambda: self.dummy())
#Eine Schaltfläche erstellen
self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
#* ↑↑ Zuerst wurde es so implementiert
# if myFunc:
# self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
# else:
# self.button = tk.Button(text=myText, command=lambda: self.dummy())
Tkinter-Schaltflächenobjekt als Ereignis beim Drücken Dem Befehlsargument ist eine Funktion zugeordnet.
Daher, wenn die createButton-Methode aufgerufen wird Sie müssen eine Funktion auf der Anruferseite vorbereiten.
Wenn Sie es jedoch zu einem gemeinsamen Teil machen, Ich wollte ein Standardargument vorbereiten, falls die Funktion nicht angegeben ist.
Zuerst habe ich es versucht.
def createButton(self, myText="Lauf", myFunc=lambda: pass):
Das hat nicht funktioniert. Es scheint schwierig, die Lambda-Funktion als Argument festzulegen.
Definieren Sie daher einen Dummy-Methoden-Dummy in der Klasse. Ich habe versucht, es zu ersetzen.
Hier, wie oben erwähnt, "können Sie das Mitglied des Feldes, das Ihre eigene Klasse hat, nicht als Argument nehmen", also Ich schrieb wie folgt.
def createButton(self, myText="Lauf", myFunc=None):
"""Nehmen Sie eine Funktion als Argument"""
# if myFunc:
# self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
# else:
# self.button = tk.Button(text=myText, command=lambda: self.dummy())
Das war in Ordnung, aber es ist ein bisschen überflüssig Das Schreiben eines Ausdrucks, der das Schaltflächenfeld zweimal definiert, ist doppelt so schwierig zu pflegen.
Daher wurde es wie folgt umgeschrieben.
def createButton(self, myText="Lauf", myFunc=None):
"""Nehmen Sie eine Funktion als Argument"""
#Funktionseinstellungen
myFunc = myFunc or (lambda: self.dummy())
#Eine Schaltfläche erstellen
self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))
QuickBrowsing.py
import os
import subprocess
import sys
#Modul-Suchpfad zurücksetzen
#Ermöglichen Sie einen Doppelklick
sys.path.append(os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + r"\PycharmProjects\CreateToolAndTest")
from Commons.JsonHandler import JsonHandler
from Commons.TkHandler_Combo_1 import TkHandler_Combo_1
import webbrowser
from time import sleep
# global
jsonHandler = None
siteList = None
tkHandler = None
siteName = None
def Main():
global jsonHandler
global siteList
global tkHandler
global siteName
#Artikelerwerb
jsonHandler = JsonHandler(
r'C:\Users\dede2\PycharmProjects\CreateToolAndTest\Tool_Python/QuickBrowsing/webSiteDetails.json')
siteList = jsonHandler.getAll_OneNest()
#Formularanzeige
tkHandler = TkHandler_Combo_1('Schnelles Durchsuchen', '640x200')
tkHandler.createFrame()
tkHandler.createLabel('Wählen Sie die Website für die Stapelanzeige aus.')
tkHandler.createCombo(myValue=siteList)
tkHandler.createButton(myFunc=getSiteName)
tkHandler.mainLoop()
#Wenn die Site nicht festgelegt ist, endet sie normal
#Wenn die Webseite nicht registriert ist, endet sie normal
if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
exit(0)
#Websites der Reihe nach öffnen
subprocess.Popen("start chrome /new-tab www.google.com --new-window", shell=True)
sleep(1)
browser = webbrowser.get(r'"' + os.getenv(r'ProgramFiles(x86)') + \
r'\Google\Chrome\Application\chrome.exe" %s')
for url in jsonHandler.getParam_TwoNest(siteName, 'PageSet'):
browser.open(url)
def getSiteName(argName=''):
global tkHandler
global siteName
tkHandler.onClosing()
siteName = argName
if __name__ == '__main__':
Main()
siteList = jsonHandler.getAll_OneNest()
Kürzung
tkHandler.createCombo(myValue=siteList)
Holen Sie sich nur die Überschrift des Site-Namens von json Machen Sie es zu einem Element in der Dropdown-Liste.
tkHandler.createButton(myFunc=getSiteName)
Kürzung
def getSiteName(argName=''):
global tkHandler
global siteName
tkHandler.onClosing()
siteName = argName
Nachdem Sie die GUI-Taste gedrückt haben, Ich setze einen Wert in eine globale Variable und behalte ihn.
Verwenden Sie nach der Überprüfung die open_new-Methode des Webbrowser-Moduls. Es heißt, dass es in einem neuen Fenster geöffnet werden kann.
** Aber wenn ich versuche es zu bewegen, funktioniert es nicht ** ** Wird als neue Registerkarte im Originalfenster geöffnet. ** ** **
Anscheinend scheint es eine solche Spezifikation zu sein. https://docs.python.org/ja/3/library/webbrowser.html
webbrowser.open_new(url) Wenn möglich, öffnen Sie die URL in einem neuen Fenster in Ihrem Standardbrowser, andernfalls öffnen Sie die URL in nur einem Fenster in Ihrem Browser.
webbrowser.open_new_tab(url) Öffnen Sie nach Möglichkeit die URL auf einer neuen Seite ("Registerkarte") im Standardbrowser, andernfalls verhalten Sie sich wie open_new ().
Wenn Chrome ursprünglich geöffnet wurde, als Registerkarte dieses Fensters Wird voraussichtlich geöffnet.
#Websites der Reihe nach öffnen
subprocess.Popen("start chrome /new-tab www.google.com --new-window", shell=True)
sleep(1)
browser = webbrowser.get(r'"' + os.getenv(r'ProgramFiles(x86)') + \
r'\Google\Chrome\Application\chrome.exe" %s')
for url in jsonHandler.getParam_TwoNest(siteName, 'PageSet'):
browser.open(url)
Öffnen Sie den Chrome-Browser in einem neuen Fenster mit der Funktion subprocess.Popen Nach einer Sekunde warten Ich habe beschlossen, alle Seiten der ausgewählten Site in diesem Fenster gleichzeitig zu öffnen.
Es kann möglich sein, es eleganter umzusetzen.
Die neuesten Tools und den Quellcode finden Sie hier. ↓ https://github.com/dede-20191130/CreateToolAndTest/tree/master/Tool_Python/QuickBrowsing
Bitte kommentieren Sie, wenn Sie Ergänzungen haben.
In der GUI wurde ein Kontrollkästchen implementiert, um zu verhindern, dass das Tool auch nach dem Drücken der Prozesstaste beendet wird.
Die folgende untergeordnete Klasse wurde durch Vererbung erstellt. (Da die Kamelregistrierungsmethode für Funktionen und Variablen nicht der Python-Standard zu sein scheint Geändert, um die Schlangenregistrierungsmethode zu verwenden. )
TkHandler_Combo_1_CanKeep.py
import tkinter as tk
# Common parts in my GitHub
# https://github.com/dede-20191130/CreateToolAndTest
from Commons.TkHandler_Combo_1 import TkHandler_Combo_1
class TkHandler_Combo_1_CanKeep(TkHandler_Combo_1):
"""
Es wurde ein Kontrollkästchen implementiert, um das Tool auch nach dem Drücken der Prozesstaste nicht zu verlassen
"""
def __init__(self, rootTitle='Titel', rootGeometry='640x480'):
super(TkHandler_Combo_1_CanKeep, self).__init__(rootTitle, rootGeometry)
self.keeping_check = None
self.bl = None
def create_keep_check(self, text='check box', is_initial=True):
self.bl = tk.BooleanVar(value=is_initial)
self.keeping_check = tk.Checkbutton(self.frame, text=text, variable=self.bl)
self.keeping_check.pack()
self.bl = tk.BooleanVar(value=is_initial)
self.keeping_check = tk.Checkbutton(self.frame, text=text, variable=self.bl)
BooleanVar ist eine Widget-Variable. Referenz: https://suzutaka-programming.com/tkinter-variable/
Variablen, die in den Optionen -text variable und -variable angegeben werden können.
Sie können die Beschriftungszeichenfolge dynamisch ändern und den eingegebenen Wert abrufen.
Umgeschrieben wie folgt.
QuickBrowsing.py
import os
import subprocess
import sys
#Modul-Suchpfad zurücksetzen
#Ermöglichen Sie einen Doppelklick
sys.path.append(os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + r"\PycharmProjects\CreateToolAndTest")
# Common parts in my GitHub
# https://github.com/dede-20191130/CreateToolAndTest
from Commons.JsonHandler import JsonHandler
from Commons.TkHandler_Combo_1_CanKeep import TkHandler_Combo_1_CanKeep
import webbrowser
from time import sleep
# global
jsonHandler = None
siteList = None
tkHandler = None
siteName = None
def Main():
global jsonHandler
global siteList
global tkHandler
global siteName
#Artikelerwerb
jsonHandler = JsonHandler(
r'C:/Users/UserName/MyFolder/Foo.json')
siteList = jsonHandler.getAll_OneNest()
#Formularanzeige
tkHandler = TkHandler_Combo_1_CanKeep('Schnelles Durchsuchen', '640x200')
tkHandler.createFrame()
tkHandler.createLabel('Wählen Sie die Website für die Stapelanzeige aus.')
tkHandler.createCombo(myValue=siteList)
tkHandler.create_keep_check('Überprüfen Sie, ob es nach der Ausführung nicht endet.')
tkHandler.createButton(myFunc=get_name_and_open)
tkHandler.mainLoop()
def get_name_and_open(argName=''):
global tkHandler
global siteName
if not tkHandler.bl.get():
tkHandler.onClosing()
siteName = argName
open_in_order()
def open_in_order():
global jsonHandler
global siteName
#Wenn die Site nicht festgelegt ist, endet sie normal
#Wenn die Webseite nicht registriert ist, endet sie normal
if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
exit(0)
#Websites der Reihe nach öffnen
subprocess.Popen("start chrome /new-tab www.google.com --new-window", shell=True)
sleep(1)
browser = webbrowser.get(r'"' + os.getenv(r'ProgramFiles(x86)') + \
r'\Google\Chrome\Application\chrome.exe" %s')
for url in jsonHandler.getParam_TwoNest(siteName, 'PageSet'):
browser.open(url)
if __name__ == '__main__':
Main()
if not tkHandler.bl.get():
tkHandler.onClosing()
Sie können die Kontrollkästchen auf der GUI frei aktivieren und deaktivieren. Wenn die Schaltfläche Ausführen gedrückt wird, während sie eingeschaltet ist, wird die Methode onclose nicht aufgerufen.