提问人: 提问时间:4/23/2022 更新时间:5/3/2022 访问量:1101
在打开带有 selenium 的弹出窗口时,跳过单击 While 循环中的元素。While 循环的问题
Skip clicking on an element in the While loop, when opening a popup with selenium. Problem with While loop
问:
此循环滚动浏览网页上的名称列表,然后单击名称旁边的每个“添加”按钮。它工作良好且正确
wait = WebDriverWait(driver, 30)
i = 1
while i <= limit:
i = i + 1
row = wait.until(EC.visibility_of_element_located((By.XPATH, f"(//div[@data-visualcompletion='ignore-dynamic' and not (@role) and not (@class)])[{i}]")))
add = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Add']"))).click()
driver.execute_script("arguments[0].scrollIntoView(true);", row, add)
有些按钮会产生问题,因为如果我单击它们,我会收到一个错误弹出窗口,说我无法将该人添加到朋友中。因此,为了解决此问题,我创建了它以自动单击“确定”并关闭弹出窗口。此代码运行良好且正确,正确单击“确定”按钮并正确关闭弹出窗口。对于读者的信息,如果我不使用“close_popup”,我会收到错误close_popup = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Ok']"))).click()
ElementClickInterceptedError
问题描述: 问题是当弹出窗口关闭时,因为按钮从“取消请求”变为“添加朋友”,您将再次(无限期)单击后者“添加朋友”,我无法添加。当弹出窗口关闭时,循环将始终单击相同的“添加”按钮(例如 John,给出错误并打开弹出窗口的按钮),而不会继续前进,也永远不会继续单击其他按钮。重要提示:发生这种情况是因为当我单击某个“添加朋友”按钮(例如仅限 John)时,它更改为“取消请求”并打开弹出窗口。因此,当我在弹出窗口中单击“确定”并关闭时,然后“取消请求”按钮将返回“添加朋友”。
因此,脚本将正常继续,并且将单击每个“添加朋友”按钮,包括我无法添加并打开弹出窗口的 John。
因此,我将按以下顺序无限期地获取这些操作:
- 点击“添加”按钮
- 打开弹出窗口
- 关闭弹出窗口,感谢单击“确定”的代码
- 再次单击“添加”按钮,因为当我关闭弹出窗口时,该按钮会将名称从“取消请求”更改为“添加”
- 从上面 1 到 4 点的无穷大开始
我想跳过单击“添加朋友”按钮,该按钮会阻止循环(在它或其他连续的循环上)并打开弹出窗口。
确切地说,我希望如果弹出窗口打开,那么当弹出窗口关闭并返回到人名列表时,我想继续单击“添加朋友”按钮,但跳过一个按钮(仅 1 个,只有打开弹出窗口并阻止循环的按钮),然后再次恢复单击第一个按钮的所有“添加 Frriend”按钮, 不再跳过(除非弹出窗口出现同样的问题)。While
因此,首先执行第一个 While,然后执行异常的第二个 While(跳过单个按钮),然后返回到第一个 While,继续单击后续按钮(在跳转按钮之后)。第二个 While 的目的是在无法按下“添加朋友”按钮时调用它,因此其目的是跳过“添加朋友”按钮,然后继续单击后续按钮(跳过按钮后)。这是我的想法,但我不确定我是否写了第二个 While 代码
我尝试添加一个 try 和 除了上面的代码。例外是这样的(我接近解决方案,但有问题):
except ElementClickInterceptedException:
print("A button cannot be pressed. You go to the next button ...")
close_popup = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Ok']"))).click()
#I skip a button, add only one (1) friend, then stop, and it's back to the main loop for to add and click on all friends
while True:
x = x + 2
row_skip = wait.until(EC.visibility_of_element_located((By.XPATH, f"(//div[@data-visualcompletion='ignore-dynamic' and not (@role) and not (@class)])[{x}]")))
addd_skip = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Add Friend']"))).click()
break
我曾想过这个解决方案,但我不知道它是否正确。我以为当我得到那个弹出窗口时,它可以暂时开始以 2 的增量跳过该按钮。在此之后,我们关闭 2 和 this while 循环的增量,然后我们返回主 while 循环。也许另一种解决方案是,如果单击同一按钮两次,则必须跳过它
我该如何解决问题?你能建议一个代码答案吗?谢谢
这是完整且可执行的代码(包括 GUI),以防有人想测试和帮助我。我不想出现垃圾邮件问题,因此我创造了选择的可能性,例如向 5 个人发送请求。此脚本仅供我自己的研究目的:
import tkinter as tk
from tkinter import ttk
from tkinter import *
from time import sleep
import time
import tkinter as tk
from tkinter import ttk
from selenium.webdriver import Firefox
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
import os
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium import webdriver
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
root = tk.Tk()
root.title("...")
root.geometry('530x500')
root.configure(bg='white')
topbar = tk.Frame(root, bg='#3b589e', height=42, width = 660)
topbar.place(x=1, y=1)
secondbar = tk.Frame(root, bg='#f0f2f5', height=42, width = 660)
secondbar.place(x=1, y=40)
#GUI
label_email = Label(root, text="email", bg='#3b589e', foreground="white")
label_email.place(x=2, y=10)
email = tk.Entry(root)
email.place(x=50, y = 9)
label_password = Label(root, text="password", bg='#3b589e', foreground="white")
label_password.place(x=260, y = 10)
password = tk.Entry(root)
password.place(x=335, y = 9)
link_label = Label(root, text="Post Link", bg='#f0f2f5', foreground="black")
link_label.place(x=2, y = 52)
link = tk.Entry(root, width = 50)
link.place(x=97, y = 50)
link.insert(tk.END, "https:/www.facebook.com/FranzKafkaAuthor/posts/3985338151528881") #example link
number_requests_label = Label(root, text="How many requests to send?", bg='white', foreground="black")
number_requests_label.place(x=2, y = 110)
number_requests = tk.Entry(root)
number_requests.place(x=4, y = 130)
number_requests.insert(tk.END, "5")
time_label = Label(root, text="Seconds between requests?", bg='white', foreground="black")
time_label.place(x=2, y = 180)
time_requests = tk.Entry(root)
time_requests.place(x=4, y = 200)
def start_with_limits():
delay = int(time_requests.get())
limit = int(number_requests.get())
#Access Facebook
profile_path = '/usr/bin/firefox/firefox'
options=Options()
options.set_preference('profile', profile_path)
options.set_preference('network.proxy.type', 4)
options.set_preference('network.proxy.socks', '127.0.0.1')
options.set_preference('network.proxy.socks_port', 9050)
options.set_preference("network.proxy.socks_remote_dns", False)
service = Service('/home/xxxx/bin/geckodriver') ########### CHANGE YOUR PATH
driver = Firefox(service=service, options=options)
driver.set_window_size(600, 990)
driver.set_window_position(1, 1)
driver.get("http://www.facebook.com")
#Cookies before login
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-cookiebanner="accept_button"]'))).click()
#Login
username_box = driver.find_element(By.ID, 'email')
username_box.send_keys(email.get())
password_box = driver.find_element(By.ID, 'pass')
password_box.send_keys(password.get())
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[1]/div[2]/div[1]/div/div/div/div[2]/div/div[1]/form/div[2]/button'))).click()
# --OPTIONAL
#Cookies before login (Sometimes it is required while sometimes not
#WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[aria-label='Allow all cookies'] span span"))).click()
#Open link
driver.get(link.get())
#Click on icon-like
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[@class='j1lvzwm4']"))).click()
time.sleep(1)
#Click su ALL
WebDriverWait(driver, 2000).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[1]/div/div[1]/div/div[4]/div/div/div[1]/div/div[2]/div/div/div/div[1]/div/div/div/div/div[2]/div[2]'))).click()
time.sleep(1)
#Scroll down and press "Add friend" buttons
wait = WebDriverWait(driver, 30)
i = 1
try:
while i <= limit:
i = i + 1
row = wait.until(EC.visibility_of_element_located((By.XPATH, f"(//div[@data-visualcompletion='ignore-dynamic' and not (@role) and not (@class)])[{i}]")))
add = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Add Friend']"))).click()
driver.execute_script("arguments[0].scrollIntoView(true);", row, add)
time.sleep(delay)
#code for close popup
#close_popup = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Ok']"))).click()
except ElementClickInterceptedException:
print("A button cannot be pressed. You go to the next button ...")
close_popup = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Ok']"))).click()
#I skip a button, add only one (1) friend, then stop, and it's back to the main loop for to add and click on all friends
while True:
x = x + 2
row_skip = wait.until(EC.visibility_of_element_located((By.XPATH, f"(//div[@data-visualcompletion='ignore-dynamic' and not (@role) and not (@class)])[{x}]")))
addd_skip = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Add Friend']"))).click()
break
begin = Button(root, text="Start", bg='#3b589e', foreground='white', width=7, command= start_with_limits)
begin.place(x=1, y=420)
root.mainloop()
答:
由于您在抓取信息时正在更改站点,因此您的循环将无法按照您希望的方式工作。
我会重新评论以首先获取您需要的信息,然后通过它进行工作:
rows = driver.find_elements(
by=By.XPATH,
value=f"(//div[@data-visualcompletion='ignore-dynamic' and not (@role) and not (@class)])"
)
for row in rows:
driver.execute_script("arguments[0].scrollIntoView(true);", row)
add_button = driver.find_element(
by=By.XPATH,
value="//span[text()='Add Friend']"
)
add_button.click()
time.sleep(delay)
try:
close_popup_button = driver.find_element(
by=By.XPATH,
value="//span[text()='Ok']"
)
close_popup_button.click()
except NoSuchElementException:
pass
对于动态加载的内容,这可能不能很好地扩展,但就此目的而言,这已经足够了。
如果你想添加这样的行为,我会看看集合,它确保没有重复的值,并且效率更高。
然后,您可以有一个循环来执行以下操作,直到它找不到任何新值。
- 查找所需元素
- 对于每个元素:
- 测试元素是否在已单击的元素集中
- 如果是,则不执行任何操作,如果不是,请单击“元素”并将其添加到集合中
- 滚动到页面底部
评论
continue
评论