[Python] À propos de la création d'un outil pour afficher toutes les pages du site Web enregistrées dans le fichier JSON et où il a été pris

1. À propos de cet article

Déclencheur

Je voulais un outil de type GUI qui ouvre des pages avec la même balise de recherche à la fois sur les sites EC et les sites de publication de travail.

* Le grattage n'est pas utilisé (même si nous envisageons de collaborer à l'avenir ...).
* Par conséquent, le sélénium n'est pas utilisé non plus.
[* Les derniers outils et le code source sont publiés sur GitHub (décrit plus loin)](à la fin de # 5)

2. Ce que vous voulez faire

・ (La classe json est une amélioration de celle précédemment créée et en a fait une partie commune) ・ Implémentation de la classe de gestion de la combo de Tkinter et en a fait une partie commune -Définissez l'interface graphique avec la méthode principale, lisez les données et ouvrez la page Web sélectionnée par l'interface graphique.

3. Outils / environnement utilisés

・ Windows10 ・ Python 3.7.0 ・ Le développement est Pycharm

4. Code créé et explication

apparence

L'interface graphique ressemble à ceci. クイックブラウジング 2020_01_07 22_26_14.png

Fichier JSON

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"
    ]
  }
}

La propriété "Only OpenPage" a été ajoutée Lors de l'examen de la mise en œuvre de la fonction de grattage à l'avenir Ouvrez-le simplement Prime de traitement de grattage, Je voulais faire une distinction.

Classe de manipulation Json

JsonHandler.py


import json


class JsonHandler:
    def __init__(self, jsonPath):
        #Lire le fichier json
        self.file = open(jsonPath, 'r', encoding="utf-8_sig")
        self.jsonData = json.load(self.file)

    #Obtenir les données JSON pour l'imbrication principale
    def getParam_OneNest(self, args):
        return self.jsonData[args]

    #Obtenir la liste des données JSON du nid principal
    def getAll_OneNest(self):
        # list = []
        # for d in self.jsonData.keys():
        #     list.append(d)
        list = [d for d in self.jsonData.keys()]
        return list

    #Obtenir des données JSON pour l'imbrication secondaire
    def getParam_TwoNest(self, args1, args2):
        return self.jsonData[args1][args2]

    def __del__(self):
        #Fermer le fichier
        self.file.close()

J'ai changé un peu celui que j'avais créé avant (*). Parce qu'il était nécessaire d'acquérir uniquement les données du nid principal à la fois. [※:https://qiita.com/dede-20191130/items/65b0f4c3c2b5c7f97546]

list = [d for d in self.jsonData.keys()]

Il s'agit d'un format d'inclusion de liste.

Classe de manipulation de boîte combo Tkinter

TkHandler_Combo_1.py


import tkinter as tk
import tkinter.ttk as ttk


class TkHandler_Combo_1:
    """Parties communes de l'interface graphique. Créer une zone de liste déroulante"""

    def __init__(self, rootTitle='Titre', rootGeometry='640x480'):
        #Créer un cadre racine
        self.root = tk.Tk()
        self.root.title(rootTitle)
        #Taille de la fenêtre racine comme valeur d'argument
        self.root.geometry(rootGeometry)
        #Fermer le paramètre d'événement
        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):
        #Créer un cadre
        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="Veuillez sélectionner"):
        #Créer une étiquette
        self.label = ttk.Label(self.frame, text=myText, padding=(5, 5))
        self.label.pack()

    def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
        #réglage de la largeur
        myWidth = myWidth or self.frame.winfo_width() - 20
        #Créer une zone de liste déroulante
        self.combo = ttk.Combobox(self.frame, width=myWidth, state=myState)
        self.combo["values"] = myValue
        #Valeur par défaut(index=0)Mis à
        self.combo.current(0)
        #Placement de la liste déroulante
        self.combo.pack(padx=5, pady=5, fill=tk.X)

    def createButton(self, myText="Courir", myFunc=None):
        """Prenez une fonction comme argument"""

        #Paramètres de fonction
        myFunc = myFunc or (lambda: self.dummy())

        #Créer un bouton
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

        #* ↑↑ Au début, c'était implémenté comme ça
        # 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())

        #Placement des boutons
        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()

Commentaire

#Fermer les paramètres de l'événement
        self.root.protocol("WM_DELETE_WINDOW", self.onClosing)

Une syntaxe qui définit une méthode appelée lorsque la fenêtre est fermée sans appuyer sur le bouton d'exécution. Effacez le cadre avant de fermer avec onClosing Empêche les erreurs lorsque le destructeur (fonction \ __ del__) fonctionne.

    def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
        #réglage de la largeur
        myWidth = myWidth or self.frame.winfo_width() - 20

Si un argument est spécifié pour myWidth, il continuera à avoir cette valeur, Si l'argument par défaut Aucun est laissé, une valeur 20 plus petite que la valeur de largeur du cadre sera entrée.

Je me suis référé à cet article pour savoir comment utiliser ou. https://blog.pyq.jp/entry/python_kaiketsu_181016

La raison pour laquelle je n'ai pas mis "self.frame.winfo_width () -20" directement dans l'argument par défaut est Il semble que vous ne pouvez pas prendre les membres de champ de votre propre classe comme arguments. Si quelqu'un sait qu'il existe un moyen possible, faites-le moi savoir.

Où je me suis fait prendre: comportement lors de la prise d'une fonction comme argument (fonction d'ordre supérieur)

    def createButton(self, myText="Courir", myFunc=None):
        """Prenez une fonction comme argument"""

        #Paramètres de fonction
        myFunc = myFunc or (lambda: self.dummy())

        #Créer un bouton
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

        #* ↑↑ Au début, c'était implémenté comme ça
        # 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())

Objet bouton Tkinter comme événement lorsqu'il est pressé Une fonction est affectée à l'argument de commande.

Par conséquent, lorsque la méthode createButton est appelée Vous devez préparer une fonction côté appelant.

Cependant, en en faisant une partie commune, Je voulais préparer un argument par défaut au cas où la fonction ne serait pas spécifiée.

Comment définir l'argument par défaut?

Au début, j'ai essayé cela.

def createButton(self, myText="Courir", myFunc=lambda: pass):

Cela n'a pas fonctionné. Il semble difficile de définir la fonction lambda comme argument.

Par conséquent, définissez une méthode factice factice dans la classe. J'ai essayé de le remplacer.

Ici, comme mentionné ci-dessus, "vous ne pouvez pas prendre le membre du champ que votre propre classe a comme argument", donc J'ai écrit comme suit.

    def createButton(self, myText="Courir", myFunc=None):
        """Prenez une fonction comme 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())

C'était bien, mais c'est un peu redondant Ecrire une expression qui définit le champ de bouton deux fois est deux fois plus difficile à gérer.

Par conséquent, il a été réécrit comme suit.

    def createButton(self, myText="Courir", myFunc=None):
        """Prenez une fonction comme argument"""

        #Paramètres de fonction
        myFunc = myFunc or (lambda: self.dummy())

        #Créer un bouton
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

Méthode principale

QuickBrowsing.py


import os
import subprocess
import sys

#Réinitialiser le chemin de recherche du module
#Rendre possible de démarrer en double-cliquant
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
    #Acquisition d'objets
    jsonHandler = JsonHandler(
        r'C:\Users\dede2\PycharmProjects\CreateToolAndTest\Tool_Python/QuickBrowsing/webSiteDetails.json')
    siteList = jsonHandler.getAll_OneNest()
    #Affichage du formulaire
    tkHandler = TkHandler_Combo_1('Navigation rapide', '640x200')
    tkHandler.createFrame()
    tkHandler.createLabel('Sélectionnez le site Web pour l'affichage par lots.')
    tkHandler.createCombo(myValue=siteList)
    tkHandler.createButton(myFunc=getSiteName)
    tkHandler.mainLoop()

    #Si le site n'est pas défini, il se termine normalement
    #Si la page Web n'est pas enregistrée, elle se termine normalement
    if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
        exit(0)

    #Ouvrez les sites Web dans l'ordre
    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()

Commentaire

siteList = jsonHandler.getAll_OneNest()
réduction
tkHandler.createCombo(myValue=siteList)

Obtenez uniquement l'en-tête du nom du site de json Faites-en un élément dans la liste déroulante.

tkHandler.createButton(myFunc=getSiteName)
réduction
def getSiteName(argName=''):
    global tkHandler
    global siteName
    tkHandler.onClosing()
    siteName = argName

Après avoir appuyé sur le bouton GUI, Je mets une valeur dans une variable globale et je la garde.

Où je suis resté coincé: Comment ouvrir Chrome dans une nouvelle fenêtre

Après vérification, utilisez la méthode open_new du module Webbrowser. Il dit qu'il peut être ouvert dans une nouvelle fenêtre.

** Mais quand j'essaye de le déplacer, ça ne marche pas, ** ** S'ouvre comme un nouvel onglet dans la fenêtre d'origine. ** **

Raison

Apparemment, cela semble être une telle spécification. https://docs.python.org/ja/3/library/webbrowser.html

webbrowser.open_new(url) Si possible, ouvrez l'url dans une nouvelle fenêtre de votre navigateur par défaut, sinon ouvrez l'url dans une seule fenêtre de votre navigateur.

webbrowser.open_new_tab(url) Si possible, ouvrez l'url dans une nouvelle page ("onglet") dans le navigateur par défaut, sinon agissez comme open_new ().

Si chrome a été ouvert à l'origine, sous forme d'onglet de cette fenêtre Devrait ouvrir.

Contre-mesures

#Ouvrez les sites Web dans l'ordre
    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)

Ouvrez le navigateur Chrome dans une nouvelle fenêtre avec le sous-processus. Après avoir attendu une seconde J'ai décidé d'ouvrir toutes les pages du site sélectionné dans cette fenêtre à la fois.

Avec du sélénium ...

Il peut être possible de l'implémenter de manière plus élégante.

5. À la fin

Les derniers outils et code source sont disponibles ici. ↓ https://github.com/dede-20191130/CreateToolAndTest/tree/master/Tool_Python/QuickBrowsing

Veuillez commenter si vous avez des suppléments.

6. [20200111] Additif: fonctions ajoutées

A. Contenu

Une case à cocher a été implémentée dans l'interface graphique pour empêcher l'outil de quitter même après avoir appuyé sur le bouton de processus.

B. Points supplémentaires

a. Classe de gestion des combos Tkinter

La classe enfant suivante a été créée par héritage. (Puisque la méthode d'enregistrement de chameau pour les fonctions et les variables ne semble pas être la norme python Changé pour utiliser la méthode d'enregistrement du serpent. )

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):
    """
Implémentation d'une case à cocher pour ne pas quitter l'outil même après avoir appuyé sur le bouton de processus
    """

    def __init__(self, rootTitle='Titre', 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()

Commentaire

        self.bl = tk.BooleanVar(value=is_initial)
        self.keeping_check = tk.Checkbutton(self.frame, text=text, variable=self.bl)

BooleanVar est une variable de widget. Référence: https://suzutaka-programming.com/tkinter-variable/

Variables pouvant être spécifiées dans la variable -text et les options -variable.

Vous pouvez modifier dynamiquement la chaîne d'étiquette et obtenir la valeur saisie.

b. Méthode principale et fonctions qui l'entourent

Réécrit comme suit.

QuickBrowsing.py


import os
import subprocess
import sys

#Réinitialiser le chemin de recherche du module
#Rendre possible de démarrer en double-cliquant
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
    #Acquisition d'objets
    jsonHandler = JsonHandler(
        r'C:/Users/UserName/MyFolder/Foo.json')
    siteList = jsonHandler.getAll_OneNest()
    #Affichage du formulaire
    tkHandler = TkHandler_Combo_1_CanKeep('Navigation rapide', '640x200')
    tkHandler.createFrame()
    tkHandler.createLabel('Sélectionnez un site Web pour l'affichage par lots.')
    tkHandler.createCombo(myValue=siteList)
    tkHandler.create_keep_check('Vérifiez si cela ne se termine pas après l'exécution.')
    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
    #Si le site n'est pas défini, il se termine normalement
    #Si la page Web n'est pas enregistrée, elle se termine normalement
    if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
        exit(0)

    #Ouvrez les sites Web dans l'ordre
    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()

Commentaire

    if not tkHandler.bl.get():
        tkHandler.onClosing()

Vous pouvez librement cocher et décocher les cases à cocher sur l'interface graphique. Si le bouton d'exécution est enfoncé lorsqu'il est activé, la méthode onclose n'est pas appelée.

Recommended Posts

[Python] À propos de la création d'un outil pour afficher toutes les pages du site Web enregistrées dans le fichier JSON et où il a été pris
[Python] À propos de la création d'un outil pour créer un nouveau courrier Outlook basé sur les données du fichier JSON et de la partie qui a été interceptée
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
Comment créer un fichier JSON en Python
[Python] Création d'un outil qui peut lister, sélectionner et exécuter des fichiers python avec tkinter et à propos de la partie qui a été interceptée
J'ai créé un script pour vérifier si l'anglais est entré dans la position spécifiée du fichier JSON en Python.
Analyser une chaîne JSON écrite dans un fichier en Python
Un mémorandum sur la mise en œuvre des recommandations en Python
Comment afficher la date de modification d'un fichier en langage C jusqu'à nanosecondes
Une histoire sur la tentative d'introduire Linter au milieu d'un projet Python (Flask)
Changer la destination de sortie standard en un fichier en Python
[Note] Importation de fichiers dans le répertoire parent en Python
[Python] Le rôle de l'astérisque devant la variable. Divisez la valeur d'entrée et affectez-la à une variable
Comment déterminer l'existence d'un élément sélénium en Python
Comment vérifier la taille de la mémoire d'une variable en Python
[Python / Jupyter] Traduisez le commentaire du programme copié dans le presse-papiers et insérez-le dans une nouvelle cellule.
L'histoire de la création d'un outil pour charger une image avec Python ⇒ l'enregistrer sous un autre nom
Une histoire sur la création d'un programme qui augmentera le nombre d'abonnés Instagram de 0 à 700 en une semaine
J'ai essayé d'afficher la valeur d'altitude du DTM dans un graphique
Afficher une liste d'alphabets en Python 3
Comment enregistrer les informations de point caractéristique de l'image dans un fichier et l'utiliser pour la mise en correspondance
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python
J'ai créé un outil pour générer du Markdown à partir du fichier JSON Scrapbox exporté
Comment obtenir une liste de fichiers dans le même répertoire avec python
Le calcul d'une question d'examen d'entrée était difficile à penser, alors j'ai laissé ça à python après tout
Récupérer l'appelant d'une fonction en Python
Copiez la liste en Python
Écrire une note sur la version python de python virtualenv
[Note] À propos du rôle du trait de soulignement "_" en Python
Sortie sous la forme d'un tableau python
Je veux afficher la progression en Python!
Comment identifier l'élément avec le plus petit nombre de caractères dans une liste Python?
Le résultat de la création d'un album de cartes de jeunes mariés italiens en Python et de son partage
Une note qui implémente une tâche en Python qui charge un fichier GCS dans BigQuery
À propos de l'utilité de la classe Python Counter - Vous n'avez plus à la compter vous-même -
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
Comment vérifier en Python si l'un des éléments d'une liste est dans une autre liste
J'ai utilisé Python pour découvrir les choix de rôle des 51 "Yachts" dans le monde.
Sortie de la table spécifiée de la base de données Oracle en Python vers Excel pour chaque fichier
[Python / GAS] Une histoire sur la création d'une API Web personnelle qui vous permet de tout savoir sur comment devenir un romancier en écriture verticale, puis en faire un bot LINE.
Modèle de script python pour lire le contenu du fichier
Comment obtenir le nombre de chiffres en Python
Lisez le fichier csv et affichez-le dans le navigateur
Un mémorandum pour exécuter un script python dans un fichier bat
[Python] Affiche toutes les combinaisons d'éléments de la liste
Afficher un histogramme des valeurs de luminosité de l'image en python
Script Python qui crée un fichier JSON à partir d'un fichier CSV
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Python Open CV a essayé d'afficher l'image sous forme de texte.
Note Python: Le mystère de l'attribution d'une variable à une variable
Utilisez le hachage pour alléger le jugement de collision d'environ 1000 balles en Python (lié au nouveau virus corona)
J'ai créé un script en Python pour convertir un fichier texte pour JSON (pour l'extrait d'utilisateur vscode)
[Python] Création d'un outil GUI qui traite automatiquement le CSV des données d'élévation de température dans Excel
J'ai créé un outil pour obtenir les liens de réponse d'OpenAI Gym en même temps
Comment afficher le maillage régional du Government Statistics Office (eStat) dans un navigateur Web
Obtenir la valeur d'une clé spécifique jusqu'à l'index spécifié de la liste de dictionnaires en Python
[OCI] Script Python pour obtenir l'adresse IP d'une instance de calcul dans Cloud Shell
[Python] Programmation pour trouver le nombre de a dans une chaîne de caractères qui se répète un nombre spécifié de fois.