遇到一个棘手的问题,如下:
在用selenium进行自动化操作时,使用pynput库进行监听鼠标的操作,监听鼠标点击事件,并同时判断点击的标签是否是想要点击的标签,根据标签内容选择调用不同浏览器打开该网址,打开网址的操作是使用os.system()打开的,这个时候再进行点击操作就会重复点击刚才点击的标签,不论点击哪里都会无限重复打开,下面是我的代码:
python代码如下:
import datetime
import os
import pytz
import subprocess
import pathlib
from selenium import webdriver
from pynput import *
from apscheduler.schedulers.background import BackgroundScheduler
folder = pathlib.Path(__file__).parent.resolve()
try:
os.system("taskkill /f /t /im chromedriver.exe")
except:
pass
options = webdriver.ChromeOptions()
options.add_experimental_option('detach', True)
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(Options=options)
driver.get('file:///' + f'{folder}/abc.html')
driver.maximize_window()
js='''
window.hovered_element = null
function track_mouse(event){
var x = event.clientX
var y = event.clientY
var element = document.elementFromPoint(x, y)
if(!element){
window.hovered_element = null
return //当前页面没有元素
}
window.hovered_element = element
}
window.onmousemove = track_mouse
'''
driver.execute_script(js)
def cl():
with mouse.Listener(on_click=on_click) as Listener:
Listener.join()
def on_click(x, y, button, pressed):
element_js = driver.execute_script('return window.hovered_element')
if pressed:
tag_name = element_js.tag_name
if tag_name == 'a':
_href = element_js.get_attribute("_href")
_type = element_js.get_attribute("_type")
if _type == 'Chrome':
subprocess.Popen('"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" '+ _href)
elif _type == 'IE':
subprocess.Popen('"C:\\Program Files\\Internet Explorer\\iexplore.exe" '+ _href)
elif _type == 'FireFox':
subprocess.Popen('"C:\\Program Files\\Mozilla Firefox\\firefox.exe" '+ _href)
scheduler = BackgroundScheduler(timezone=pytz.timezone("Asia/Shanghai"))
scheduler.add_job(cl, 'date', next_run_time=datetime.datetime.now())
scheduler.start()
abc.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>
<a _href="https://www.baidu.com" _type="Chrome">百度(使用Chrome打开)</a>
</div>
<div>
<a _href="https://www.baidu.com" _type="IE">百度(使用IE打开)</a>
</div>
</body>
</html>
目前使用cmd调用exe文件打开都没有问题,想实现一个页面循环调用监听鼠标事件打开(点完这个点那个,但是中间不会重复调用),想问各位这代码怎么修改可以实现呢,现在我只知道调用cmd后鼠标会停留在selenium自动化页面点击的那个标签上,切换到我用cmd打开的浏览器里再点击就会重复点击selenium刚才点击的那个标签
你的鼠标监听器在执行完一次点击操作后没有正确地停止,而是继续监听鼠标事件,并且重复调用你的on_click函数。这样就会导致无限循环打开浏览器
创建一个线程事件,你试下效果如何
import datetime
import os
import pytz
import subprocess
import pathlib
import threading # 导入threading模块
from selenium import webdriver
from pynput import *
from apscheduler.schedulers.background import BackgroundScheduler
folder = pathlib.Path(__file__).parent.resolve()
try:
os.system("taskkill /f /t /im chromedriver.exe")
except:
pass
options = webdriver.ChromeOptions()
options.add_experimental_option('detach', True)
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(Options=options)
driver.get('file:///' + f'{folder}/abc.html')
driver.maximize_window()
js='''
window.hovered_element = null
function track_mouse(event){
var x = event.clientX
var y = event.clientY
var element = document.elementFromPoint(x, y)
if(!element){
window.hovered_element = null
return //当前页面没有元素
}
window.hovered_element = element
}
window.onmousemove = track_mouse
'''
driver.execute_script(js)
def cl():
with mouse.Listener(on_click=on_click) as Listener:
Listener.join()
def on_click(x, y, button, pressed):
element_js = driver.execute_script('return window.hovered_element')
if pressed:
tag_name = element_js.tag_name
if tag_name == 'a':
_href = element_js.get_attribute("_href")
_type = element_js.get_attribute("_type")
if _type == 'Chrome':
subprocess.Popen('"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" '+ _href)
elif _type == 'IE':
subprocess.Popen('"C:\\Program Files\\Internet Explorer\\iexplore.exe" '+ _href)
elif _type == 'FireFox':
subprocess.Popen('"C:\\Program Files\\Mozilla Firefox\\firefox.exe" '+ _href)
# 设置线程事件,通知主线程鼠标已经点击
clicked.set()
# 返回False,停止监听器
return False
# 创建一个线程事件对象
clicked = threading.Event()
while True: # 用一个循环来实现页面循环调用监听鼠标事件打开
# 每次循环前清除线程事件状态
clicked.clear()
listener = mouse.Listener(on_click=on_click)
listener.start()
try:
# 等待线程事件,直到鼠标点击为止
clicked.wait()
finally:
# 停止监听器
listener.stop()
在 on_click
函数中,我添加了停止监听的代码,以及在新的浏览器启动后重新启动监听的代码。
def cl():
with mouse.Listener(on_click=on_click) as Listener:
Listener.join()
listener = None # 把监听器设为全局变量
def on_click(x, y, button, pressed):
global listener
element_js = driver.execute_script('return window.hovered_element')
if pressed:
tag_name = element_js.tag_name
if tag_name == 'a':
_href = element_js.get_attribute("_href")
_type = element_js.get_attribute("_type")
listener.stop() # 在打开新浏览器前停止监听
if _type == 'Chrome':
subprocess.Popen('"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" '+ _href)
elif _type == 'IE':
subprocess.Popen('"C:\\Program Files\\Internet Explorer\\iexplore.exe" '+ _href)
elif _type == 'FireFox':
subprocess.Popen('"C:\\Program Files\\Mozilla Firefox\\firefox.exe" '+ _href)
listener = mouse.Listener(on_click=on_click) # 启动新的监听器
listener.start() # 启动新的监听器
scheduler = BackgroundScheduler(timezone=pytz.timezone("Asia/Shanghai"))
scheduler.add_job(cl, 'date', next_run_time=datetime.datetime.now())
scheduler.start()
这个修改的代码假设你在每次点击后只打开一个新的浏览器,并且在新的浏览器打开后立即返回原来的页面进行下一次点击。如果你的实际情况有所不同,你可能需要调整监听器停止和重启的时间点。
采用chatgpt:
根据你提供的代码和描述,问题出现在鼠标监听事件的重复调用。这是因为你的监听器(mouse.Listener)在调用join()方法后会一直等待鼠标点击事件,而当你使用subprocess.Popen()调用其他浏览器时,监听器仍然在运行,因此会接收到从其他浏览器传递过来的鼠标点击事件,导致重复点击。
为了解决这个问题,你可以在调用其他浏览器之前暂停监听器。具体做法是在调用subprocess.Popen()之前调用Listener.stop()方法停止监听器。这样,当你切换到其他浏览器后,监听器就不会接收到鼠标点击事件了。
修改后的代码如下所示:
import datetime
import os
import pytz
import subprocess
import pathlib
from selenium import webdriver
from pynput import *
from apscheduler.schedulers.background import BackgroundScheduler
folder = pathlib.Path(__file__).parent.resolve()
try:
os.system("taskkill /f /t /im chromedriver.exe")
except:
pass
options = webdriver.ChromeOptions()
options.add_experimental_option('detach', True)
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(options=options)
driver.get('file:///' + f'{folder}/abc.html')
driver.maximize_window()
js='''
window.hovered_element = null
function track_mouse(event){
var x = event.clientX
var y = event.clientY
var element = document.elementFromPoint(x, y)
if(!element){
window.hovered_element = null
return //当前页面没有元素
}
window.hovered_element = element
}
window.onmousemove = track_mouse
'''
driver.execute_script(js)
def cl():
with mouse.Listener(on_click=on_click) as Listener:
Listener.join()
def on_click(x, y, button, pressed):
element_js = driver.execute_script('return window.hovered_element')
if pressed:
tag_name = element_js.tag_name
if tag_name == 'a':
_href = element_js.get_attribute("_href")
_type = element_js.get_attribute("_type")
if _type == 'Chrome':
Listener.stop() # 停止监听器
subprocess.Popen('"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" '+ _href)
elif _type == 'IE':
Listener.stop() # 停止监听器
subprocess.Popen('"C:\\Program Files\\Internet Explorer\\iexplore.exe" '+ _href)
elif _type == 'FireFox':
Listener.stop() # 停止监听器
subprocess.Popen('"C:\\Program Files\\Mozilla Firefox\\firefox.exe" '+ _href)
scheduler = BackgroundScheduler(timezone=pytz.timezone("Asia/Shanghai"))
scheduler.add_job(cl, 'date', next_run_time=datetime.datetime.now())
scheduler.start()
这样,当你从 Selenium 打开其他浏览器时,监听器会停止,而在切换回 Selenium 页面后,监听器会继续运行,等待下一个鼠标点击事件。
在上述代码中,我在每个打开浏览器的条件分支中添加了Listener.stop(),以确保在调用其他浏览器之前停止监听器。
参考深度学习模型给你答复:
这个问题涉及到selenium驱动浏览器和pynput监听鼠标事件之间的交互,出现重复点击的原因是selenium驱动浏览器后,鼠标焦点还停留在浏览器上,而 pynput 继续监听鼠标事件,导致重复触发点击事件。
要解决这个问题,可以考虑以下方法:
# 暂停监听
listener.stop()
# 打开新浏览器
os.system(...)
# 等待新页面加载完成
time.sleep(5)
# 继续监听
listener.start()
# 获取所有窗口句柄
all_windows = driver.window_handles
# 切换到新打开窗口
driver.switch_to.window(all_windows[-1])
import mouse
# 打开新浏览器后移动鼠标位置
mouse.move(1000, 500)
# 获取chromedriver进程id并终止
driver.service.process.pid
os.kill(pid, signal.SIGTERM)
综合使用这些方法,可以避免selenium和pynput之间的鼠标事件冲突,解决重复点击的问题。
基于bing、GPT部分内容和本人思考总结:
可以考虑在监听鼠标点击事件时,记录上一次点击的标签内容,并在下一次点击时判断当前点击的标签内容是否与上一次相同。如果相同则不进行任何操作,如果不同则根据标签内容选择调用不同浏览器打开该网址。 示例代码:
from selenium import webdriver
from pynput import mouse
import os
last_label = None
def on_click(x, y, button, pressed):
global last_label
if pressed and button == mouse.Button.left:
element = driver.find_element_by_xpath("//xpath/to/element")
label = element.text
if label != last_label:
last_label = label
if label == "xxx":
os.system("start xxx.exe")
elif label == "yyy":
os.system("start yyy.exe")
return False
driver = webdriver.Chrome()
driver.get("https://example.com")
with mouse.Listener(on_click=on_click) as listener:
listener.join()
在上面的代码中,last_label用于记录上一次点击的标签内容。当监听到鼠标点击事件时,获取当前点击的标签内容,并与上一次点击的标签内容进行比较。如果不同,则记录当前标签内容为上一次点击的标签内容,并根据标签内容选择调用不同浏览器打开该网址。如果相同,则不进行任何操作。 需要注意的是,os.system()是一个同步的调用方式,会阻塞当前进程直到被调用的程序执行完毕。如果需要异步调用程序,可以考虑使用subprocess.Popen()。
在你的代码中,点击事件会触发on_click
函数,而on_click
函数会调用subprocess.Popen
来打开浏览器。由于subprocess.Popen
是一个异步操作,会立即返回,因此当你切换到通过subprocess.Popen
打开的浏览器后,鼠标点击事件仍然会传递到原来的页面,导致重复点击。
为了解决这个问题,你可以尝试在on_click
函数中添加一个适当的延迟,以确保切换到新打开的浏览器后再进行鼠标点击监听。你可以使用time.sleep()
函数来添加延迟,例如:
import time
def on_click(x, y, button, pressed):
element_js = driver.execute_script('return window.hovered_element')
if pressed:
tag_name = element_js.tag_name
if tag_name == 'a':
_href = element_js.get_attribute("_href")
_type = element_js.get_attribute("_type")
if _type == 'Chrome':
subprocess.Popen('"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" '+ _href)
elif _type == 'IE':
subprocess.Popen('"C:\\Program Files\\Internet Explorer\\iexplore.exe" '+ _href)
elif _type == 'FireFox':
subprocess.Popen('"C:\\Program Files\\Mozilla Firefox\\firefox.exe" '+ _href)
# 添加适当的延迟
time.sleep(1)
这样,当你切换到通过subprocess.Popen
打开的浏览器后,会等待1秒钟再进行鼠标点击监听,从而避免了重复点击问题。
请注意,根据实际情况,你可能需要调整延迟的时间来适应浏览器的加载速度和响应时间。
根据你提供的代码描述,可能出现无限重复打开的问题是因为在监听鼠标点击事件时没有正确地处理事件的触发条件。以下是一个示例代码,展示了如何在使用 Selenium 和 pynput 监听鼠标点击事件时避免重复点击的问题:
import os
from pynput.mouse import Listener, Button
from selenium import webdriver
def open_url(url):
# 这里使用 Selenium 打开网页
driver = webdriver.Chrome()
driver.get(url)
def on_click(x, y, button, pressed):
if button == Button.left and pressed:
element = driver.find_element_by_xpath("//your/xpath") # 替换为你想要点击的标签的 XPath
if element.text == "Your desired text": # 替换为你想要点击的标签的内容
url = element.get_attribute("href") # 获取标签的链接地址
open_url(url)
listener.stop()
# 这里需要创建一个 Selenium WebDriver 实例
driver = webdriver.Chrome()
# 这里设置监听鼠标点击事件
with Listener(on_click=on_click) as listener:
listener.join()
在上述示例代码中,首先通过 Selenium 创建一个 WebDriver 实例(这里使用 ChromeDriver),然后在 on_click
回调函数中,通过 XPath 定位到你想要点击的标签,并检查其文本内容是否符合预期。如果符合预期,获取标签的链接地址,并调用 open_url
函数使用 Selenium 打开该链接。最后,通过 listener.stop()
停止监听鼠标点击事件。
请注意,在使用 Selenium 打开链接之前,你需要根据实际情况进行必要的 WebDriver 初始化操作(例如设置 ChromeDriver 的路径、配置选项等)。