July 31, 2022 at 4:01 AM
In the previous lesson, we introduced Python classes.
Then we created a Method_Class_Hello class method.
So, let's continue with this section.
Create a function called "__init__": Also inside this function, create two variables:
Why use two underscores to create function names?
"Because I want to have these two variables when I instantiate the object".
This sentence is very "abstract", why do you have these two variables when you instantiate it?
Many times, we have this application scenario, for example, before selenium "starts", I want to assign him an agent, then the best time to initialize the agent information is before selenium starts (starts to execute business logic).
Extended reading:
The program is a binary file, and there are different loading methods on different platforms (such as windows, Linux, UNIX), and we will not explain it in depth here. We only need to remember two concepts of program startup here:
1. Allocate memory space at startup
2. Allocate memory space at runtime
Facing the __init__ function, it pre-allocates memory space to two variables at startup:
self.name and self.age
Well, no need to investigate the principle (because even if you pursue it now, it will only make you unable to understand the knowledge immediately), in the future we will call __init__ "class constructor (or class constructor)", when a class is instantiated , the __init__ method will execute immediately and allocate memory space.
Python classes provide many built-in methods, all of which are named with double underscores (eg: __xxxx__). Classes support many features, including "polymorphism".
Maybe I'm going to tell you this now, it sounds like a headache, but once you start reading other people's code one day, you will find "how can I not understand? Why". At this point, you must remember that the code is written by the author by hand, carefully observe the execution flow of the program, and try to search for keywords you do not understand, this is the fastest way to get started.
So, now, I will re-use the method of the class to encapsulate the previous project from the perspective of your just getting started, pay attention to how my class method passes parameters and uses the return value:
Note that __init__ I only use one pass for placeholder.
Now you can try to parameterize "hard-coded" in your code.
For example, my idea is to pass the account text and proxy information as parameters to the SeleniumMethodClass class when instantiating the object, then, I can do this:
Now, can you find other "hard-coded" places in our test project? Try to modify it. Then encapsulate.
This is the only course I don't want you to copy-paste. Try to understand and repeat the process. Before moving on to the next lesson, I hope you have a thorough understanding.
Then we created a Method_Class_Hello class method.
So, let's continue with this section.
Create a function called "__init__": Also inside this function, create two variables:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 2022-07-31
# Breached.to Bullet Class:
# THE FAST ONLINE VERSION 1.0CB
class MyClass:
two = "is two"
three = "is three"
Four = "is four"
def __init__(self):
self.name = "a"
self.age = 1
def Method_Class_Hello(self):
"""
This is a class method, nothing special, just outputs debug information.
:return:
"""
print("Method_Class_Hello is called.")
if __name__ == '__main__':
# Create a variable to instantiate.
MyClass_object = MyClass()
# Debug output the value of this class member (attribute) variable
print(MyClass_object.Four)
# called Method_Class_Hello
MyClass_object.Method_Class_Hello()Why use two underscores to create function names?
"Because I want to have these two variables when I instantiate the object".
This sentence is very "abstract", why do you have these two variables when you instantiate it?
Many times, we have this application scenario, for example, before selenium "starts", I want to assign him an agent, then the best time to initialize the agent information is before selenium starts (starts to execute business logic).
Extended reading:
The program is a binary file, and there are different loading methods on different platforms (such as windows, Linux, UNIX), and we will not explain it in depth here. We only need to remember two concepts of program startup here:
1. Allocate memory space at startup
2. Allocate memory space at runtime
Facing the __init__ function, it pre-allocates memory space to two variables at startup:
self.name and self.age
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 2022-07-31
# Breached.to Bullet Class:
# THE FAST ONLINE VERSION 1.0CB
class MyClass:
two = "is two"
three = "is three"
Four = "is four"
def __init__(self):
self.name = "a"
self.age = 1
def Method_Class_Hello(self):
"""
This is a class method, nothing special, just outputs debug information.
:return:
"""
print("Method_Class_Hello is called.")
if __name__ == '__main__':
# Create a variable to instantiate.
MyClass_object = MyClass()
# Debug output the value of this class member (attribute) variable
print(MyClass_object.Four)
# called Method_Class_Hello
MyClass_object.Method_Class_Hello()
# I own:
print(MyClass_object.name)
print(MyClass_object.age)Well, no need to investigate the principle (because even if you pursue it now, it will only make you unable to understand the knowledge immediately), in the future we will call __init__ "class constructor (or class constructor)", when a class is instantiated , the __init__ method will execute immediately and allocate memory space.
Python classes provide many built-in methods, all of which are named with double underscores (eg: __xxxx__). Classes support many features, including "polymorphism".
Maybe I'm going to tell you this now, it sounds like a headache, but once you start reading other people's code one day, you will find "how can I not understand? Why". At this point, you must remember that the code is written by the author by hand, carefully observe the execution flow of the program, and try to search for keywords you do not understand, this is the fastest way to get started.
So, now, I will re-use the method of the class to encapsulate the previous project from the perspective of your just getting started, pay attention to how my class method passes parameters and uses the return value:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 2022-07-31
# Breached.to Bullet Class: mejuri Project
# THE FAST ONLINE VERSION 1.0CB
import os
import time
# Import selenium package
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# New Import
from selenium.webdriver.common.by import By
class SeleniumMethodClass:
"""
Try using class method encapsulation
"""
def __init__(self):
pass
def Loading_AccountFile(self):
"""
Load the account text file from the local disk, and read each line of data in it for parsing. The parsed data is in the form of a dictionary.
Then we add the dictionary to a list for the program to call in a loop.
:return: (type)List -> Account List
Account file format:
account password
Note: Use ":" to separate the account and password.
account.txt:
[email protected]:a123456
[email protected]:a1234567
[email protected]:a12345678
"""
# Define a list of accounts for saving the results
RESULT_ACCOUNT_LIST = []
_inputFileName = r"r:\account.txt"
# Check if the account file exists
if os.path.exists(_inputFileName) is False:
print("Debug Output: Don't open Account File.")
else:
# Loading Account File
with open(_inputFileName, "r", encoding="utf8") as r:
_rawData = r.readlines()
for accountNode in _rawData:
_tmpStr = str(accountNode.strip()).split(":")
# The result of each line parsed is added to the result list.
RESULT_ACCOUNT_LIST.append(_tmpStr)
# Finally, return this result list
# Check the length of the returned account list
if len(RESULT_ACCOUNT_LIST) == 0:
return False
else:
return RESULT_ACCOUNT_LIST
def Input_Account(self, object_driver, account_info):
# Real combat code:
BASE_URL = "https://mejuri.com/"
object_driver.get(BASE_URL)
# Changes from previous: different places
success_Box_Title_Str = ['Mejuri | Everyday Fine Jewelry | Online Jewelry Shop', ]
success_Box_URL_Str = ["https://mejuri.com/", ]
if object_driver.title in success_Box_Title_Str or object_driver.current_url in success_Box_URL_Str:
print("Debug Output: Specific business code part...")
# 1. Look for the login element:
_element_Login_btn = object_driver.find_element(By.XPATH,
'/html/body/div[1]/div[3]/div/section/header/nav/div[2]/button/span')
# 2. Use the sleep method to force a delay.
# This is an officially not recommended method, and is only used here as an explanation.
time.sleep(1)
# 3. Once the login element is found, click it using the click() method.
_element_Login_btn.click()
time.sleep(1)
# 4. Navigate to the username input element
_element_input_accountBox = object_driver.find_element(By.XPATH, '//*[@id="input-email"]')
######################################################
# Old way, hardcoded. Let's cancel this line of code.
# _element_input_accountBox.send_keys("[email protected]")
# Use new methods.
_element_input_accountBox.send_keys(account_info[0])
######################################################
time.sleep(1)
_element_continue_btn = object_driver.find_element(By.XPATH,
'/html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[2]/form/div[2]/button/span')
_element_continue_btn.click()
print("Debug Output: Input Account Success.")
return True
else:
print("Debug Output: Open URL Fail...")
return False
def Verify_Result(self, object_driver):
"""
Check result
:return: Bool
To locate two elements, we take the parameter: string
Then, if we do not take the string as the basis for judging the result, we can also use other methods.
"""
VERIFYBOX = ['Please create an account', ]
# XPATH
# /html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[1] = Looks like you’re new!
# /html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[2] = Please create an account
_element_check_str = object_driver.find_element(By.XPATH, '/html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[2]')
if _element_check_str.text in VERIFYBOX:
# If the result matches the expected value
# Then, it means that the account you are testing is not registered
print("Debug Output: Verify_Result function result:[{}]".format(_element_check_str.text))
return False
else:
return True
def Save_Result(self, account_result_list):
"""
Save results to local text file: Note that if the results list is empty, no saving is necessary.
:param account_result_list:
:return:
"""
if len(account_result_list) == 0:
print("Debug Output: Save the result to a text file: The result is empty, and writing to the file is ignored..")
else:
print("Debug Output: Save the results to a text file: [{}] results, start writing the results to the file.".format(len(account_result_list)))
# In append write mode, write the result to the local specified file
# Parameters: "a", which represents the append mode
with open(r"r:
esult.txt", "a", encoding="utf8") as wa:
for resultNode in account_result_list:
wa.write(str(resultNode[0] + ":" + resultNode[1] + '
'))
def WebdriverInitialization(self, proxy_info):
"""
Encapsulate DRIVER and add custom HTTP proxy function
:param proxy_info:
:return:
Create a selenium object, then you can use the methods of this object, if you don't understand, you can ignore it, copy and paste with me
"""
# Custom option parameters
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_experimental_option('useAutomationExtension', False)
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('disable-cache')
options.add_argument('-ignore-certificate-errors')
options.add_argument('-ignore -ssl-errors')
# Add custom proxy: use http proxy
options.add_argument(f'--proxy-server=http://' + proxy_info)
# Download the Chrome kernel locally, then, we load it
_chromePath = r"r:\chromedriver.exe"
# Use Service(), initialize
chromeService = Service(_chromePath)
# The only thing to note about the two parameters here is options. In the front, we customized these options, then DRIVER will use it as we customized
DRIVER = webdriver.Chrome(options=options, service=chromeService)
# Returns the DRIVER that has been initialized
# Note that the return value is an "object"
return DRIVER
def Main(self):
"""
main method
:return:
"""
# Initialization DRIVER
_http_proxy = "127.0.0.1:8080"
DRIVER = self.WebdriverInitialization(_http_proxy)
################### Business logic part ###################
# Save results
RESULT = []
# Step 1: Load the account text file
_accountList = self.Loading_AccountFile()
if _accountList is False:
print("Debug Output: Loading Account File Fail.")
else:
# Step 2: Loop through the loaded account list file
for accountNode in _accountList:
# Calling the function: Parameters: DRIVER, Account Info
if self.Input_Account(DRIVER, accountNode) is False:
print("Debug Output: Input_Account Fail.")
else:
# Step 3: Validation results
print("Debug Output: Call the check result function..")
if self.Verify_Result(DRIVER) is True:
# If the account exists, then you need to save the account to the final result list.
RESULT.append(accountNode)
else:
print(
"Debug Output: If the account does not exist, skip this test and ignore saving the results.")
pass
# Step 4: Save the results to a text file:
# Note that the code is indented, at the same level as the for loop statement
self.Save_Result(RESULT)
if __name__ == '__main__':
# Instantiate SeleniumMethodClass. and call the Main method.
TestUnit_Object = SeleniumMethodClass()
TestUnit_Object.Main()Note that __init__ I only use one pass for placeholder.
Now you can try to parameterize "hard-coded" in your code.
For example, my idea is to pass the account text and proxy information as parameters to the SeleniumMethodClass class when instantiating the object, then, I can do this:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 2022-07-31
# Breached.to Bullet Class: mejuri Project
# THE FAST ONLINE VERSION 1.0CB
import os
import time
# Import selenium package
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# New Import
from selenium.webdriver.common.by import By
class SeleniumMethodClass:
"""
Try using class method encapsulation
"""
def __init__(self, input_file_name):
# New changes
self.ACCOUNTFILE = input_file_name
def Loading_AccountFile(self):
"""
Load the account text file from the local disk, and read each line of data in it for parsing. The parsed data is in the form of a dictionary.
Then we add the dictionary to a list for the program to call in a loop.
:return: (type)List -> Account List
Account file format:
account password
Note: Use ":" to separate the account and password.
account.txt:
[email protected]:a123456
[email protected]:a1234567
[email protected]:a12345678
"""
# Define a list of accounts for saving the results
RESULT_ACCOUNT_LIST = []
# Removed "hardcoding", made account text "parameterized"
#_inputFileName = r"r:\account.txt"
# Check if the account file exists
#
if os.path.exists(self.ACCOUNTFILE) is False:
print("Debug Output: Don't open Account File.")
else:
# Loading Account File: Use class member variables
with open(self.ACCOUNTFILE, "r", encoding="utf8") as r:
_rawData = r.readlines()
for accountNode in _rawData:
_tmpStr = str(accountNode.strip()).split(":")
# The result of each line parsed is added to the result list.
RESULT_ACCOUNT_LIST.append(_tmpStr)
# Finally, return this result list
# Check the length of the returned account list
if len(RESULT_ACCOUNT_LIST) == 0:
return False
else:
return RESULT_ACCOUNT_LIST
def Input_Account(self, object_driver, account_info):
# Real combat code:
BASE_URL = "https://mejuri.com/"
object_driver.get(BASE_URL)
# Changes from previous: different places
success_Box_Title_Str = ['Mejuri | Everyday Fine Jewelry | Online Jewelry Shop', ]
success_Box_URL_Str = ["https://mejuri.com/", ]
if object_driver.title in success_Box_Title_Str or object_driver.current_url in success_Box_URL_Str:
print("Debug Output: Specific business code part...")
# 1. Look for the login element:
_element_Login_btn = object_driver.find_element(By.XPATH,
'/html/body/div[1]/div[3]/div/section/header/nav/div[2]/button/span')
# 2. Use the sleep method to force a delay.
# This is an officially not recommended method, and is only used here as an explanation.
time.sleep(1)
# 3. Once the login element is found, click it using the click() method.
_element_Login_btn.click()
time.sleep(1)
# 4. Navigate to the username input element
_element_input_accountBox = object_driver.find_element(By.XPATH, '//*[@id="input-email"]')
######################################################
# Old way, hardcoded. Let's cancel this line of code.
# _element_input_accountBox.send_keys("[email protected]")
# Use new methods.
_element_input_accountBox.send_keys(account_info[0])
######################################################
time.sleep(1)
_element_continue_btn = object_driver.find_element(By.XPATH,
'/html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[2]/form/div[2]/button/span')
_element_continue_btn.click()
print("Debug Output: Input Account Success.")
return True
else:
print("Debug Output: Open URL Fail...")
return False
def Verify_Result(self, object_driver):
"""
Check result
:return: Bool
To locate two elements, we take the parameter: string
Then, if we do not take the string as the basis for judging the result, we can also use other methods.
"""
VERIFYBOX = ['Please create an account', ]
# XPATH
# /html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[1] = Looks like you’re new!
# /html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[2] = Please create an account
_element_check_str = object_driver.find_element(By.XPATH, '/html/body/div[1]/div[8]/div[1]/div/div/div/div[2]/div[1]/div[2]')
if _element_check_str.text in VERIFYBOX:
# If the result matches the expected value
# Then, it means that the account you are testing is not registered
print("Debug Output: Verify_Result function result:[{}]".format(_element_check_str.text))
return False
else:
return True
def Save_Result(self, account_result_list):
"""
Save results to local text file: Note that if the results list is empty, no saving is necessary.
:param account_result_list:
:return:
"""
if len(account_result_list) == 0:
print("Debug Output: Save the result to a text file: The result is empty, and writing to the file is ignored..")
else:
print("Debug Output: Save the results to a text file: [{}] results, start writing the results to the file.".format(len(account_result_list)))
# In append write mode, write the result to the local specified file
# Parameters: "a", which represents the append mode
with open(r"r:
esult.txt", "a", encoding="utf8") as wa:
for resultNode in account_result_list:
wa.write(str(resultNode[0] + ":" + resultNode[1] + '
'))
def WebdriverInitialization(self, proxy_info):
"""
Encapsulate DRIVER and add custom HTTP proxy function
:param proxy_info:
:return:
Create a selenium object, then you can use the methods of this object, if you don't understand, you can ignore it, copy and paste with me
"""
# Custom option parameters
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_experimental_option('useAutomationExtension', False)
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('disable-cache')
options.add_argument('-ignore-certificate-errors')
options.add_argument('-ignore -ssl-errors')
# Add custom proxy: use http proxy
options.add_argument(f'--proxy-server=http://' + proxy_info)
# Download the Chrome kernel locally, then, we load it
_chromePath = r"r:\chromedriver.exe"
# Use Service(), initialize
chromeService = Service(_chromePath)
# The only thing to note about the two parameters here is options. In the front, we customized these options, then DRIVER will use it as we customized
DRIVER = webdriver.Chrome(options=options, service=chromeService)
# Returns the DRIVER that has been initialized
# Note that the return value is an "object"
return DRIVER
def Main(self):
"""
main method
:return:
"""
# Initialization DRIVER
_http_proxy = "127.0.0.1:8080"
DRIVER = self.WebdriverInitialization(_http_proxy)
################### Business logic part ###################
# Save results
RESULT = []
# Step 1: Load the account text file
_accountList = self.Loading_AccountFile()
if _accountList is False:
print("Debug Output: Loading Account File Fail.")
else:
# Step 2: Loop through the loaded account list file
for accountNode in _accountList:
# Calling the function: Parameters: DRIVER, Account Info
if self.Input_Account(DRIVER, accountNode) is False:
print("Debug Output: Input_Account Fail.")
else:
# Step 3: Validation results
print("Debug Output: Call the check result function..")
if self.Verify_Result(DRIVER) is True:
# If the account exists, then you need to save the account to the final result list.
RESULT.append(accountNode)
else:
print(
"Debug Output: If the account does not exist, skip this test and ignore saving the results.")
pass
# Step 4: Save the results to a text file:
# Note that the code is indented, at the same level as the for loop statement
self.Save_Result(RESULT)
if __name__ == '__main__':
# Instantiate SeleniumMethodClass. and call the Main method.
_account_File_Path = r"r:\account.txt"
# When instantiating, pass parameters directly to the __init__ class constructor.
TestUnit_Object = SeleniumMethodClass(_account_File_Path)
# Call the class method Main()
TestUnit_Object.Main()Now, can you find other "hard-coded" places in our test project? Try to modify it. Then encapsulate.
This is the only course I don't want you to copy-paste. Try to understand and repeat the process. Before moving on to the next lesson, I hope you have a thorough understanding.
