[Python] About creating a tool to display all the pages of the website registered in the JSON file & where it got caught

1. About this article

Trigger

I wanted a GUI-type tool that opens pages with the same search tag at once on EC sites and work posting sites.

* Scraping is not used (although we are thinking of collaborating in the future ...).
* Therefore, selenium is not used either.
[* The latest tools and source code are posted on GitHub (described later)](at the end of # 5)

2. What you want to do

・ (The json class is an improvement of the previously made one and made it a common part) ・ Implemented Tkinter combo box handling class and made it a common component -Set the GUI with the main method, read the data, and open the web page selected by the GUI.

3. Tools / environment used

・ Windows 10 -Python 3.7.0 ・ Development is Pycharm

4. Created code and explanation

appearance

The GUI looks like this. クイックブラウジング 2020_01_07 22_26_14.png

Json file

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

The "OnlyOpenPage" property was added When the scraping function implementation is also considered in the future Just open it Scraping processing is given, I wanted to make a distinction.

Json handling class

JsonHandler.py


import json


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

    #Primary nest json data acquisition
    def getParam_OneNest(self, args):
        return self.jsonData[args]

    #Get json data list of primary nest
    def getAll_OneNest(self):
        # list = []
        # for d in self.jsonData.keys():
        #     list.append(d)
        list = [d for d in self.jsonData.keys()]
        return list

    #Secondary nest json data acquisition
    def getParam_TwoNest(self, args1, args2):
        return self.jsonData[args1][args2]

    def __del__(self):
        #File close
        self.file.close()

I changed the one I created before (*) a little. Because it was necessary to get only the data of the primary nest at once. [※:https://qiita.com/dede-20191130/items/65b0f4c3c2b5c7f97546]

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

This is a list comprehension format.

Tkinter combo box handling class

TkHandler_Combo_1.py


import tkinter as tk
import tkinter.ttk as ttk


class TkHandler_Combo_1:
    """Common parts for GUI. Create a combo box"""

    def __init__(self, rootTitle='title', rootGeometry='640x480'):
        #Creating a root frame
        self.root = tk.Tk()
        self.root.title(rootTitle)
        #The size of the root window as the argument value
        self.root.geometry(rootGeometry)
        #Close event settings
        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):
        #Creating a frame
        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="Please select"):
        #Creating a label
        self.label = ttk.Label(self.frame, text=myText, padding=(5, 5))
        self.label.pack()

    def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
        #width setting
        myWidth = myWidth or self.frame.winfo_width() - 20
        #Creating a combo box
        self.combo = ttk.Combobox(self.frame, width=myWidth, state=myState)
        self.combo["values"] = myValue
        #The default value(index=0)Set to
        self.combo.current(0)
        #Combo box placement
        self.combo.pack(padx=5, pady=5, fill=tk.X)

    def createButton(self, myText="Run", myFunc=None):
        """Take a function as an argument"""

        #Function settings
        myFunc = myFunc or (lambda: self.dummy())

        #Creating a button
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

        #* ↑↑ Initially implemented like this
        # 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())

        #Button placement
        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()

Commentary

#Close event settings
        self.root.protocol("WM_DELETE_WINDOW", self.onClosing)

Syntax to set a method that will be called when the window is closed without pressing the run button. Erase the frame before closing with onClosing Prevent errors when the destructor (\ __ del__ function) works.

    def createCombo(self, myWidth=None, myState='readonly', myValue=None, ):
        #width setting
        myWidth = myWidth or self.frame.winfo_width() - 20

If an argument is specified for myWidth, it will continue to have that value, If the default argument None is left, a value that is 20 less than the width value of the frame will be entered.

I referred to this article for how to use or. https://blog.pyq.jp/entry/python_kaiketsu_181016

The reason why I didn't put "self.frame.winfo_width () -20" directly in the default argument is It seems that you cannot take the members of the field that your own class has as an argument. If anyone knows that there is a possible way, please let me know.

Where I got caught: Behavior when taking a function as an argument (higher-order function)

    def createButton(self, myText="Run", myFunc=None):
        """Take a function as an argument"""

        #Function settings
        myFunc = myFunc or (lambda: self.dummy())

        #Creating a button
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

        #* ↑↑ Initially implemented like this
        # 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 button object as an event when pressed A function is assigned to the command argument.

Therefore, when the createButton method is called You have to prepare a function on the caller side.

However, when making it a common part, I wanted to prepare a default argument in case the function is not specified.

How to set the default argument?

At first I tried this.

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

This didn't work. It seems difficult to set a lambda function as an argument.

So, define a dummy method dummy in the class I tried to substitute it.

Here, as mentioned above, "I can't take the member of the field that my class has as an argument", so I wrote as follows.

    def createButton(self, myText="Run", myFunc=None):
        """Take a function as an 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())

This was fine, but it's a bit verbose Writing an expression that defines the button field twice is twice as difficult as maintenance.

Therefore, it was rewritten as follows.

    def createButton(self, myText="Run", myFunc=None):
        """Take a function as an argument"""

        #Function settings
        myFunc = myFunc or (lambda: self.dummy())

        #Creating a button
        self.button = tk.Button(text=myText, command=lambda: myFunc(self.combo.get()))

Main method

QuickBrowsing.py


import os
import subprocess
import sys

#Reset module search path
#Make it possible to start by double-clicking
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
    #Item acquisition
    jsonHandler = JsonHandler(
        r'C:\Users\dede2\PycharmProjects\CreateToolAndTest\Tool_Python/QuickBrowsing/webSiteDetails.json')
    siteList = jsonHandler.getAll_OneNest()
    #Form display
    tkHandler = TkHandler_Combo_1('Quick browsing', '640x200')
    tkHandler.createFrame()
    tkHandler.createLabel('Select a website for batch display.')
    tkHandler.createCombo(myValue=siteList)
    tkHandler.createButton(myFunc=getSiteName)
    tkHandler.mainLoop()

    #If the site is not set, it ends normally
    #If the web page is not registered, it ends normally
    if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
        exit(0)

    #Open websites in order
    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()

Commentary

siteList = jsonHandler.getAll_OneNest()
abridgement
tkHandler.createCombo(myValue=siteList)

Get only the site name headline from json Make it an item in the drop-down list.

tkHandler.createButton(myFunc=getSiteName)
abridgement
def getSiteName(argName=''):
    global tkHandler
    global siteName
    tkHandler.onClosing()
    siteName = argName

After pressing the GUI button, I put a value in a global variable and keep it.

Where I got stuck: How to open chrome in a new window

After checking, use the open_new method of the webbrowser module. It says that it can be opened in a new window.

** But when I try to move it, it doesn't work, ** ** It opens as a new tab in the original window. ** **

Reason

Apparently, it seems to be such a specification. https://docs.python.org/ja/3/library/webbrowser.html

webbrowser.open_new(url) If possible, open the url in a new window in your default browser, otherwise open the url in just one window in your browser.

webbrowser.open_new_tab(url) If possible, open the url in a new page ("tab") in the default browser, otherwise behave like open_new ().

If chrome was originally open, as a tab for that window Expected to open.

Countermeasures

#Open websites in order
    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)

Open the chrome browser in a new window with the subprocess.Popen function After waiting for a second I decided to open all the pages of the selected site in that window at once.

With selenium ...

It may be possible to implement it more elegantly.

5. At the end

The latest tools and source code are available here. ↓ https://github.com/dede-20191130/CreateToolAndTest/tree/master/Tool_Python/QuickBrowsing

Please comment if you have any supplements.

6. [20200111] Addendum: Added functions

A. Contents

Implemented a check box in the GUI to prevent the tool from exiting even after pressing the process button.

B. Additional points

a. Tkinter combo box handling class

The following child class was created by inheritance. (Since the camel registration method for functions / variables does not seem to be the python standard Changed to use the snake signature method. )

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):
    """
Implemented a check box to not exit the tool even after pressing the process button
    """

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

Commentary

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

BooleanVar is a Widget variable. Reference: https://suzutaka-programming.com/tkinter-variable/

Variables that can be specified in the -text variable and -variable options.

You can dynamically change the label string and get the entered value.

b. Main method and functions around it

Rewrote as follows.

QuickBrowsing.py


import os
import subprocess
import sys

#Reset module search path
#Make it possible to start by double-clicking
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
    #Item acquisition
    jsonHandler = JsonHandler(
        r'C:/Users/UserName/MyFolder/Foo.json')
    siteList = jsonHandler.getAll_OneNest()
    #Form display
    tkHandler = TkHandler_Combo_1_CanKeep('Quick browsing', '640x200')
    tkHandler.createFrame()
    tkHandler.createLabel('Select a website for batch display.')
    tkHandler.createCombo(myValue=siteList)
    tkHandler.create_keep_check('Check if it does not end after execution.')
    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
    #If the site is not set, it ends normally
    #If the web page is not registered, it ends normally
    if siteName == None or not jsonHandler.getParam_TwoNest(siteName, 'OnlyOpenPage'):
        exit(0)

    #Open websites in order
    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()

Commentary

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

You can freely check and uncheck the check boxes on the GUI. If the execute button is pressed when it is on, the onclose method is not called.

Recommended Posts

[Python] About creating a tool to display all the pages of the website registered in the JSON file & where it got caught
[Python] About creating a tool to create a new Outlook email based on the data of the JSON file and the part that got caught
I made a program to check the size of a file in Python
How to create a JSON file in Python
[Python] Creating a tool that can list, select, and execute python files with tkinter & about the part that got caught
I created a script to check if English is entered in the specified position of the JSON file in Python.
Parse a JSON string written to a file in Python
A reminder about the implementation of recommendations in Python
How to display the modification date of a file in C language up to nanoseconds
A story about trying to introduce Linter in the middle of a Python (Flask) project
Change the standard output destination to a file in Python
[Note] Import of a file in the parent directory in Python
[Python] The role of the asterisk in front of the variable. Divide the input value and assign it to a variable
How to determine the existence of a selenium element in Python
[Cloudian # 9] Try to display the metadata of the object in Python (boto3)
How to check the memory size of a variable in Python
[Python / Jupyter] Translate the comment of the program copied to the clipboard and insert it in a new cell
The story of making a tool to load an image with Python ⇒ save it as another name
A story about creating a program that will increase the number of Instagram followers from 0 to 700 in a week
Test & Debug Tips: Create a file of the specified size in Python
I tried to display the altitude value of DTM in a graph
Display a list of alphabets in Python 3
How to save the feature point information of an image in a file and use it for matching
How to pass the execution result of a shell command in a list in Python
I made a tool to generate Markdown from the exported Scrapbox JSON file
How to get a list of files in the same directory with python
The math of some entrance exam question is awkward to think about, so I left it to python after all
Get the caller of a function in Python
Make a copy of the list in Python
A note about the python version of python virtualenv
[Note] About the role of underscore "_" in Python
About the behavior of Model.get_or_create () of peewee in Python
Output in the form of a python array
I want to display the progress in Python!
How to identify the element with the smallest number of characters in a Python list?
The result of making a map album of Italy honeymoon in Python and sharing it
A memo that implements the job of loading a GCS file into BigQuery in Python
About the usefulness of the Python Counter class-You don't have to count it yourself anymore-
I want to replace the variables in the python template file and mass-produce it in another file.
How to check in Python if one of the elements of a list is in another list
I used Python to find out about the role choices of the 51 "Yachts" in the world.
Output the specified table of Oracle database in Python to Excel for each file
[Python / GAS] A story about creating a personal Web API that allows you to read all about becoming a novelist in vertical writing, and then making it a LINE bot.
Template of python script to read the contents of the file
How to get the number of digits in Python
Read the csv file and display it in the browser
A memorandum to run a python script in a bat file
[Python] Outputs all combinations of elements in the list
Display a histogram of image brightness values in python
Python script to create a JSON file from a CSV file
To do the equivalent of Ruby's ObjectSpace._id2ref in Python
Python OpenCV tried to display the image in text.
Python Note: The mystery of assigning a variable to a variable
Use hash to lighten collision detection of about 1000 balls in Python (related to the new coronavirus)
I made a script in Python to convert a text file for JSON (for vscode user snippet)
[Python] Creating a GUI tool that automatically processes CSV of temperature rise data in Excel
I made a tool to get the answer links of OpenAI Gym all at once
How to display the regional mesh of the official statistics window (eStat) in a web browser
Get the value of a specific key up to the specified index in the dictionary list in Python
[OCI] Python script to get the IP address of a compute instance in Cloud Shell
[Python] Programming to find the number of a in a character string that repeats a specified number of times.