一、前言
最近几个月里,我一直在学习网络爬虫方面的知识,每有收获都会将所得整理成文发布,不知不觉已经发了7篇日志了:
网络爬虫学习:从百度搜索结果抓取标题、链接、内容,并保存到xlsx文件中
网络爬虫学习:从新浪新闻搜索抓取所有新闻结果的标题、链接、内容、来源、时间
网络爬虫学习:POST方式从腾*新闻搜索结果获取标题、链接、内容、来源、时间
网络爬虫学习:多线程爬取,并将结果更新到主线程UI上
网络爬虫学习:应用selenium从搜*狐搜索爬取新闻结果的数据
网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开
网络爬虫学习:借助DeepSeek完善爬虫软件,增加停止任务功能
这两天,我又解决了模拟鼠标右键点击的问题,特记录以备忘。
二、问题描述
在完成第一个爬虫软件之后,我又开始制作第二个爬虫软件,这个软件是为我自己准备的一个专用工具,目的是从特定的web应用中导出查询到的数据。在这个应用查询数据后,要点击页面中的导出按钮才能将数据导出。点击按钮后在页面上会展示一个超链接,需要点击这个超链接后才能将数据文件保存到本地电脑中。
这个链接既可以用鼠标左键点击弹出浏览器的下载框进行下载,也可以用鼠标右键点击后选择“将链接另存为”菜单项,弹出Windows系统的“另存为”窗口,进行下载。
由于我还不会模拟鼠标右键点击,于是决定选择往这个方向研究。
注意:我开发的爬虫软件调用的Edge浏览器,鼠标右键点击弹出的菜单中,显示的是“将链接另存为”,在其它的浏览器(如360浏览器),显示的菜单名有所不同。
三、借助DeepSeek获取解决办法
我之前已经尝试过借助DeepSeek来解决问题了,效果还不错,这次也一样,将问题抛给DeepSeek,让它帮我想办法。这次我同样是问了3次,就解决了问题。
第1问:“我正在尝试用selenium做一个登录网页并进行自动操作的小软件,软件需要实现模拟鼠标右键点击,并选中菜单中的“将链接另存为”菜单项,请问我该怎么实现此功能。”
稍候数秒,DeepSeek给出了答案,建议我使用Selenium的ActionChains模拟右键点击,然后使用PyAutoGUI或AutoIt等工具选择“将链接另存为”菜单项。DeepSeek给出的示例用的PyAutoGUI库,这个库刚好我的电脑里也装了,只是我对这个库不了解一直没用过,这次我便用照着示例修改了我的软件,确实实现了模拟右键点击功能。
右键点击是实现了,菜单也出现了,但是示例中出现的 pyautogui.press('down') 要根据需要按多次的操作,这种死板的操作我不喜欢,因为右键菜单可能会因为安装了一些插件后发生变化,如果在不同的电脑上,因为安装的插件不同,“将链接另存为”菜单项的位置也不同,那该怎么办呢?
于是我提出第2问:“此方法经过测试有用,不过我有一个新的问题。就是这个方法只适用于菜单项目固定的情况,如果因为安装了新的插件导致“将链接另存为”菜单项位置发生变化,又该怎么办?”
DeepSeek提供了3个方案,其中有两个方案都使用到了PyAutoGUI库,我选择了方案1。
使用方案1,需要手工将浏览器右键菜单项截图,然后从中剪裁出“将链接另存为”菜单项并保存为png文件(文件名save_link_as.png)。
实现点击“将链接另存为”菜单项后就弹出Windows系统的“另存为”窗口了。但接下来怎么做呢,可能DeepSeek不清楚点击“将链接另存为”菜单项,会出现怎样的情形,因此它没有猜到我接着要干啥。
无奈,我只得提出第3问:“感谢你的答案,我已经能够实现模拟右键并点击“将链接另存为”菜单项了,不过接下来我又遇到了一个新问题。点击“将链接另存为”菜单项后,会弹出“另存为”窗口,需要用户在这个窗口中选择文件保存的路径,并命名文件名称。这些操作我都希望通过软件自动进行。我想在软件中设置好文件路径和文件名,当弹出“另存为”窗口后,通过软件将文件路径和文件名填到窗口对应位置,然后点击“保存”按钮,完成文件的保存操作。”
DeepSeek又给了3个方法,方法1又用到了PyAutoGUI库,当然选它啦,。
四、功能实现
借助DeepSeek的答案,我实现了模拟右键点击,将链接指向的文件保存到了本地,这里以右键点击百度首页中的logo图标,将其指向的htm文件保存到本地为示例,说明功能的实现(完整代码见本文第五部分):
1.设置文件将要保存的路径及文件名。
htm文件将要保存在当前工作目录下的results子目录中,事先将路径和文件名设置好。
python"># 获取当前工作路径
work_path = os.getcwd()
print(work_path)
# 检查当前工作路径下是否有results子目录,如没有就创建
subdirectory_name = os.path.join(work_path, "results")
if not os.path.exists(subdirectory_name):os.makedirs(subdirectory_name)
# 生成文件路径
file_path = os.path.join(subdirectory_name, "baidu_logo.htm")
print(file_path)
2.配置浏览器
我选择的系统自带的Edge浏览器,同时提前下载了对应版本的驱动文件并保存在了工作目录下的drivers子目录中。
python"># 配置 Selenium 浏览器驱动
path_to_executable = os.path.abspath("drivers/msedgedriver.exe") # 指定驱动路径(驱动已提前下载到当前工作路径子目录drivers下)
service = Service(executable_path=path_to_executable)
driver = webdriver.Edge(service=service)
# driver.maximize_window() # 全屏
driver.set_window_size(1200, 800) # 指定分辨率
关于如何下载驱动文件msedgedriver.exe,详见我的另外一篇日志。
网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开
3.打开百度首页,并选中logo图片
python"># 在浏览器中打开百度首页
driver.implicitly_wait(5)
driver.get("https://www.baidu.com")
time.sleep(3)# 选中百度首页中的logo图片
element = driver.find_element(By.XPATH, "//*[@id='lg']/img")
4.通过selenium库的ActionChains类模拟鼠标右键点击
注意:由于软件运行速度很快,而浏览网页响应较慢,因此在代码的多个地方插入了time.sleep方法,进行延迟,以免页面还没有显示,就执行了相关的点击之类的代码。延迟的时间需要根据网络情况进行调整。
python"># 创建ActionChains对象
action = ActionChains(driver)
# 模拟鼠标右键点击
action.context_click(element).perform()
# 等待菜单弹出
time.sleep(1)
5.将百度logo图片链接的htm文件保存到本地
python"># 指定“将链接另存为”菜单项的图片文件
template_image = 'save_link_as.png' # 此图片文件需要手工截取Edge浏览器右键菜单中的“将链接另存为”菜单项,保存为图片文件
# 使用图像识别查找菜单项,查找图片在屏幕上的位置
location = pyautogui.locateCenterOnScreen(template_image, confidence=0.8) # 需要OpenCV支持
if location:print(f"找到菜单项,位置为: {location}")time.sleep(3)# 点击菜单项pyautogui.click(location)# 等待“另存为”窗口弹出time.sleep(1)# 模拟按键 Shift + Home(选中所有文本)pyautogui.hotkey('shift', 'home')# 模拟按键 Delete(删除选中的文本)pyautogui.press('delete')# 定位“文件名”输入框并填写文件路径和文件名pyautogui.write(file_path)time.sleep(3)# 按下回车键确认保存pyautogui.press('enter')time.sleep(1)# 点击“保存”按钮,使用图像识别定位按钮位置save_button_location = pyautogui.locateCenterOnScreen('save_button.png') # 此图片文件需要手工截取“另存为”窗口中的“保存”按钮,保存为图片文件if save_button_location:pyautogui.click(save_button_location)
else:print("未找到菜单项")
这部分的代码中有两个png文件,都是需要提前准备的。
save_link_as.png:需要手工将浏览器右键菜单项截图,然后从中剪裁出“将链接另存为”菜单项并保存为png文件。
save_button.png:需要手工将“另存为”窗口截图,然后从中剪裁出“保存”按钮并保存为png文件。
最终的实现效果如下:
1.打开百度首页模拟鼠标右键点击logo图片。
2.点击“将链接另存为”菜单项,弹出“另存为”窗口,将事先设置好的路径和文件名填入窗口的文件名文本框中。
3.htm已保存到本地
五、代码展示
最后放上示例代码供参考,可以直接运行。
python">import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.action_chains import ActionChains
import pyautogui
import os# 获取当前工作路径
work_path = os.getcwd()
print(work_path)
# 检查当前工作路径下是否有results子目录,如没有就创建
subdirectory_name = os.path.join(work_path, "results")
if not os.path.exists(subdirectory_name):os.makedirs(subdirectory_name)
# 生成文件路径
file_path = os.path.join(subdirectory_name, "baidu_logo.htm")
print(file_path)# 配置 Selenium 浏览器驱动
path_to_executable = os.path.abspath("drivers/msedgedriver.exe") # 指定驱动路径(驱动已提前下载到当前工作路径子目录drivers下,相关方法见我的另外一篇日志)
service = Service(executable_path=path_to_executable)
driver = webdriver.Edge(service=service)
# driver.maximize_window() # 全屏
driver.set_window_size(1200, 800) # 指定分辨率# 在浏览器中打开百度首页
driver.implicitly_wait(5)
driver.get("https://www.baidu.com")
time.sleep(3)# 选中百度首页中的logo图片
element = driver.find_element(By.XPATH, "//*[@id='lg']/img")
# 创建ActionChains对象
action = ActionChains(driver)
# 模拟鼠标右键点击
action.context_click(element).perform()
# 等待菜单弹出
time.sleep(1)# 使用PyAutoGUI模拟右键点击,弹出菜单后,选择“将链接另存为”菜单项
# 注意:PyAutoGUI的坐标和操作依赖于屏幕分辨率
# 指定“将链接另存为”菜单项的图片文件
template_image = 'save_link_as.png' # 此图片文件需要手工截取Edge浏览器右键菜单中的“将链接另存为”菜单项,保存为图片文件
# 使用图像识别查找菜单项,查找图片在屏幕上的位置
location = pyautogui.locateCenterOnScreen(template_image, confidence=0.8)
if location:print(f"找到菜单项,位置为: {location}")time.sleep(3)# 点击菜单项pyautogui.click(location)# 等待“另存为”窗口弹出time.sleep(1)# 模拟按键 Shift + Home(选中所有文本)pyautogui.hotkey('shift', 'home')# 模拟按键 Delete(删除选中的文本)pyautogui.press('delete')# 定位“文件名”输入框并填写文件路径和文件名pyautogui.write(file_path)time.sleep(3)# 按下回车键确认保存pyautogui.press('enter')time.sleep(1)# 点击“保存”按钮,使用图像识别定位按钮位置save_button_location = pyautogui.locateCenterOnScreen('save_button.png') # 此图片文件需要手工截取“另存为”窗口中的“保存”按钮,保存为图片文件if save_button_location:pyautogui.click(save_button_location)
else:print("未找到菜单项")time.sleep(2)
driver.quit()