我可以将方法调用存储在元组中而无需在运行时调用方法吗?
此练习称为命令行电子邮件器,它来自自动用python python ch 12 2nd ed。 >
编写一个程序,该程序在 命令行,然后使用硒登录到您的电子邮件帐户 并将字符串的电子邮件发送到提供的地址。 (您可能 想要为此程序设置一个单独的电子邮件帐户。)
在进行此练习时,我了解到硒方法要求查找HTML元素有时会起作用,但是有时它们会扔nosuchelementException
。为了解决这个问题,我创建了三个元组来存储硒方法调用。使用selenium_exception_loop()
函数(见下文),我将循环遍历元组,并一次调用一种方法。如果该方法抛出nosuchelementfound
异常,则循环将等待两秒钟,然后重试。
当然,问题是在运行时执行硒方法调用。有什么方法可以将硒方法调用存储在集合中,而无需在运行时实际执行呼叫?还是我需要在这里采取完全不同的方法?
#!python3
# 04_command_line_emailer.py -- send emails from the command line
# usage: input four command line arguments:
# sys.argv[1] = email to log into
# sys.argv[2] = password
# sys.argv[3] = email body
# sys.argv[4] = recipient email address
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import sys
import re
import time
class commandLineEmailer:
def __init__(self):
self.browser = webdriver.Firefox()
self.gmail_method_calls = ()
self.outlook_method_calls = ()
self.yahoo_method_calls = (
lambda: self.browser.find_element(By.CLASS_NAME, 'signin').click(),
lambda: self.browser.find_element(By.NAME, 'username').send_keys(self.return_email_info()[0]),
lambda: self.browser.find_element(By.NAME, 'signin').click(),
lambda: self.browser.find_element(By.NAME, 'password').send_keys(sys.argv[2]),
lambda: self.browser.find_element(By.NAME, 'verifyPassword').click(),
lambda: self.browser.find_element(By.CSS_SELECTOR, 'Compose').click()
)
def return_email_info(self) -> tuple:
'''
Input sys.argv[1] into regex. sys.argv[1] contains the sending email
address. return the username and the email client name.
:return: tuple, username at index 0, email client name at index 1
'''
return re.compile("(.*)(\@)(.*)(\.)").match(sys.argv[1]).group(1), \
re.compile("(.*)(\@)(.*)(\.)").match(sys.argv[1]).group(3)
# open browser session and navigate to email client
def go_to_email_client(self) -> None:
EMAIL_CLIENTS = {
'outlook': 'https://www.outlook.com/',
'gmail': 'https://www.gmail.com/',
'yahoo': 'https://yahoomail.com/'
}
self.browser.get(EMAIL_CLIENTS[self.return_email_info()[1]])
def selenium_exception_loop(self, selenium_method_collection) -> None:
'''
:param selenium_method_collection: input collection containing selenium
method calls to search for html elements. Wait two seconds between each
method call. Except the NoSuchElementException error.
:return: None
'''
for selenium_method_call in selenium_method_collection:
while True:
try:
time.sleep(2) # wait two seconds
selenium_method_call()
break
except NoSuchElementException:
continue
def sign_in_and_send(self) -> None:
'''
Retrieve the email client to log into. Call the selenium_exception_loop()
function and pass it the email client tuple containing the selenium
method calls
:return None:
'''
if self.return_email_info()[1] == 'gmail':
pass
elif self.return_email_info()[1] == 'outlook':
pass
elif self.return_email_info()[1] == 'yahoo':
self.selenium_exception_loop(self.yahoo_method_calls)
def main() -> None:
command_line_emailer = commandLineEmailer()
command_line_emailer.go_to_email_client()
command_line_emailer.sign_in_and_send()
if __name__ == "__main__":
main()
This exercise is called Command Line Emailer and it comes from Automate the Boring Stuff with Python CH 12 2nd ed.
Write a program that takes an email address and string of text on the
command line and then, using selenium, logs in to your email account
and sends an email of the string to the provided address. (You might
want to set up a separate email account for this program.)
While working through this exercise, I learned that the selenium method calls for finding html elements will sometimes work, but sometimes they will throw noSuchElementException
. To work around this, I created three tuples to store the selenium method calls. Using the selenium_exception_loop()
function (see below), I would loop through the tuple and call one method at a time. If the method throws a noSuchElementFound
exception, the loop will wait two seconds then try again.
The issue, of course, is that the selenium method calls are executed at runtime. Is there any way to store the selenium method calls in a collection without actually executing the calls during runtime? Or do I need to take an entirely different approach here?
#!python3
# 04_command_line_emailer.py -- send emails from the command line
# usage: input four command line arguments:
# sys.argv[1] = email to log into
# sys.argv[2] = password
# sys.argv[3] = email body
# sys.argv[4] = recipient email address
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import sys
import re
import time
class commandLineEmailer:
def __init__(self):
self.browser = webdriver.Firefox()
self.gmail_method_calls = ()
self.outlook_method_calls = ()
self.yahoo_method_calls = (
lambda: self.browser.find_element(By.CLASS_NAME, 'signin').click(),
lambda: self.browser.find_element(By.NAME, 'username').send_keys(self.return_email_info()[0]),
lambda: self.browser.find_element(By.NAME, 'signin').click(),
lambda: self.browser.find_element(By.NAME, 'password').send_keys(sys.argv[2]),
lambda: self.browser.find_element(By.NAME, 'verifyPassword').click(),
lambda: self.browser.find_element(By.CSS_SELECTOR, 'Compose').click()
)
def return_email_info(self) -> tuple:
'''
Input sys.argv[1] into regex. sys.argv[1] contains the sending email
address. return the username and the email client name.
:return: tuple, username at index 0, email client name at index 1
'''
return re.compile("(.*)(\@)(.*)(\.)").match(sys.argv[1]).group(1), \
re.compile("(.*)(\@)(.*)(\.)").match(sys.argv[1]).group(3)
# open browser session and navigate to email client
def go_to_email_client(self) -> None:
EMAIL_CLIENTS = {
'outlook': 'https://www.outlook.com/',
'gmail': 'https://www.gmail.com/',
'yahoo': 'https://yahoomail.com/'
}
self.browser.get(EMAIL_CLIENTS[self.return_email_info()[1]])
def selenium_exception_loop(self, selenium_method_collection) -> None:
'''
:param selenium_method_collection: input collection containing selenium
method calls to search for html elements. Wait two seconds between each
method call. Except the NoSuchElementException error.
:return: None
'''
for selenium_method_call in selenium_method_collection:
while True:
try:
time.sleep(2) # wait two seconds
selenium_method_call()
break
except NoSuchElementException:
continue
def sign_in_and_send(self) -> None:
'''
Retrieve the email client to log into. Call the selenium_exception_loop()
function and pass it the email client tuple containing the selenium
method calls
:return None:
'''
if self.return_email_info()[1] == 'gmail':
pass
elif self.return_email_info()[1] == 'outlook':
pass
elif self.return_email_info()[1] == 'yahoo':
self.selenium_exception_loop(self.yahoo_method_calls)
def main() -> None:
command_line_emailer = commandLineEmailer()
command_line_emailer.go_to_email_client()
command_line_emailer.sign_in_and_send()
if __name__ == "__main__":
main()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
收集了这个答案 lambda 在每个方法调用的前面,然后重写
selenium_method
ASselenium_method()
,以便它是可召唤的,就像这样:This answer was gathered from reddit, but essentially, put
lambda
in front of each method call, and rewriteselenium_method
asselenium_method()
so that it is callable, like so: