一、前言
最近幾個月里,我一直在學習網絡爬蟲方面的知識,每有收獲都會將所得整理成文發布,不知不覺已經發了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子目錄中,事先將路徑和文件名設置好。
# 獲取當前工作路徑
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子目錄中。
# 配置 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圖片
# 在瀏覽器中打開百度首頁
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方法,進行延遲,以免頁面還沒有顯示,就執行了相關的點擊之類的代碼。延遲的時間需要根據網絡情況進行調整。
# 創建ActionChains對象
action = ActionChains(driver)
# 模擬鼠標右鍵點擊
action.context_click(element).perform()
# 等待菜單彈出
time.sleep(1)
5.將百度logo圖片鏈接的htm文件保存到本地
# 指定“將鏈接另存為”菜單項的圖片文件
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已保存到本地
五、代碼展示
最后放上示例代碼供參考,可以直接運行。
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()