python Selenium 和 PyAutoGUI合璧爬取網頁攻略
前一段時間在做關於美國請願網站的研究,需要爬取change.org這個請願網站上每個請願的資訊。大致爬蟲順序是:先爬取每個標籤下所有請願的名字和具體網址,訪問每個具體網址爬取請願的發起時間、內容等資訊。這裡就需要用到電腦模擬點選載入按鈕、快捷鍵下載網頁到本地的操作,也就需要用到Selenium和PyAutoGUI這兩個強大的工具。
網頁頁面和Selenium基本介紹
先要介紹一下網頁的頁面,讓大家對程式碼和工具所應用到的場景有一個基本瞭解。change.org是美國一個社會企業,主要運營線上請願的發起和傳播,像最近BLM運動的很多請願都來自change.org。一個請願會有主要標籤,比如下圖的Racial Justice:
點選對應標籤後就能看到標籤下的請願。但是網頁只會顯示10個左右,想要載入全部需要點幾十次網頁底部的"Load More“按鈕,這就需要Selenium了:
我最先接觸的是R的Selenium,後來轉到Python,兩個的基本思想框架是一樣的,就是用到不同的包,語法有一點點不同,所以這裡安裝和基礎運用就兩個混著介紹了。首先是要按照Selenium一系列的配置:要根據你的系統(Windows, 蘋果...)選對應的安裝方法,根據你用的瀏覽器下載安裝對應的驅動,安裝JAVA環境,安裝R或Python對應的包...挺繁瑣的,但網上有很多非常詳細的教程,這裡我貼一些對我非常有用的以供參考:
整體準備(以R為例):
https://www.cnblogs.com/mxly/p/10156517.html
JAVA配置和Selenium下載:
https://blog.csdn.net/weixin_40628687/article/details/78971934
Chrome瀏覽器與驅動:
https://blog.csdn.net/huilan_same/article/details/51896672
Chrome驅動呼叫問題:
https://blog.csdn.net/weixin_42508908/article/details/85986029
其它瀏覽器驅動:
https://www.cnblogs.com/qiezizi/p/8632058.html
Windows使用者變數與系統變數區別:
https://blog.csdn.net/sxhlovehmm/article/details/44274633
Selenium官方文件:
https://www.selenium.dev/documentation/en/
Python Selenium包使用:
https://www.browserstack.com/guide/python-selenium-to-run-web-automation-test
Python Selenium包官方文件:
https://selenium-python.readthedocs.io/
RSelenium包使用:
https://blog.csdn.net/weixin_40628687/article/details/78998740
https://www.computerworld.com/article/2971265/how-to-drive-a-web-browser-with-r-and-rselenium.html(這個非常詳細!)
找到XPath路徑的Chrome外掛:
http://www.cnplugins.com/devtool/xpath-helper/
測試CSS和XPath語法的網站:
https://www.freeformatter.com/xpath-tester.html
這麼多連結一下看很頭疼,我的建議就是先看第一個連結,把基本安裝一步步完成,遇到問題就在搜尋引擎裡搜,中文搜不到用英文搜,然後放到具體專案裡實戰,比如想實現一個目的就去學對應的語法,慢慢地就能學會了。話不多說,就從我的專案開始吧。
用Selenium點選按鈕(這裡用R語法,下面的PyAUTOgui用Python):
首先要找到按鈕的XPath或CSS路徑,可以藉助外掛,下面這個就是按鈕的XPath路徑:
//*[@class='col-xs-12 col-md-8 col-md-offset-2']/button[@class='btn btn-big btn-full bg-brighter']
要使用RSelenium的函式findElement先找到這個路徑下的按鈕然後用clickElement來操作這個點選:
loadmore <- remDr$findElement(using = 'xpath', "//*[@class='col-xs-12 col-md-8 col-md-offset-2']/button[@class='btn btn-big btn-full bg-brighter']") loadmore$clickElement()下面是全部程式碼:
library(RSelenium) library(risingMap) library(XML) library(rvest) ## 開啟瀏覽器 remDr <- remoteDriver(browserName ="chrome") remDr$open() ## 先開啟網頁 url <-"https://www.change.org/petitions?selected=victories" remDr$navigate(url) setwd("D:/.../change/") #點選載入按鈕 # find button # driver.findElement(By.xpath("//a[contains(text(),'Next')]")).click(); # click button pb <- txtProgressBar(0, 5000, style = 3,char= paste0('load', '|')) i=1 for (i in 1:5000){ # loadmore <- remDr$findElement(using = 'xpath', "//*[@class='js-load-more']/button[@class='btn btn-full btn-big']") loadmore <- remDr$findElement(using = 'xpath', "//*[@class='col-xs-12 col-md-8 col-md-offset-2']/button[@class='btn btn-big btn-full bg-brighter']") loadmore$clickElement() # wait Sys.sleep(0.5) setTxtProgressBar(pb, i) }
上面程式碼裡我還用到了Sys.sleep,這是害怕電腦頻繁點使得網頁識別並封掉我;此外還用到進度條,想知道自己點了多少次了。當頁面載入完畢後,就可以直接爬或者把網頁下載到本地用readlines函式。爬取對應資訊的方法在我部落格裡給社團同學做的R語言爬蟲分享裡。
當然,不是所有按鈕都像這個load more這麼好點,有一個按鈕的路徑我大概找了半天,後來拜託實習的帶教老師幫忙找到了。就是下圖這個按鈕:
它的問題在於:如果直接複製外掛找到的路徑,是根本找不到它的。
class那麼長,全複製到程式碼里根本識別不出來,原因在於其中只有一個class屬性是屬於這個按鈕的,那就是box。當用bos做測試後發現才能成功點選按鈕。這裡還需要注意一個問題,上圖是我手動輸入網址訪問的頁面,當使用自動化訪問該網頁後對應按鈕的class屬性可能還有變化,比如這個按鈕在自動化測試時的class屬性變成display-block,但這背後的原理是一樣的:就是不要使用全部class屬性。
PyAutoGUI基本介紹及安裝:
這個工具用從這個部落格文章和youtube視訊入手去了解是最好的(我是找了很多技術文章才最終找到它們的/(ㄒoㄒ)/~~):
PyAutoGUI基本介紹
https://www.zachnielsen.org/introduction-to-selenium-and-pyautogui.html
https://www.youtube.com/watch?v=dZLyfbSQPXI&t=673s 找到方法後安裝卻先出了問題,用pip install後卻出現module not found error:在Jupyter安裝並引入包時報module not found error錯:
https://blog.csdn.net/qq_37135484/article/details/97242788 照著上面這個安裝還是不行,決定把包下載下來裝:多種方法安裝pyautoGUI:
https://www.cnblogs.com/zhumengdexiaobai/p/10505531.html 但好久沒有用過這個方法裝,也忘得差不多了,而且光是cd到路徑就費了好大勁:Python如何安裝下載下來的包:
https://www.php.cn/python-tutorials-424614.html 最後總算是找到這篇詳細的文章,講解為何Jupyter會匯入包時報module not found error ,因為是通過Annaconda安裝的Jupyter:用Annaconda安裝的Jupyter匯入包時報錯:
https://www.cnblogs.com/jisongxie/p/9892660.html這樣總算把PyAutoGUI安裝完成了,但接下來使用又會遇到很多困難。
PyAutoGUI操作:
我要做的是批量訪問網頁,按ctrl+s鍵把網頁儲存到行動硬碟上,網頁檔名為對應的請願名。看視訊講解是一回事,實操又是一回事:比如視訊沒有告訴我我要實現的這一操作具體每一步要怎麼做:電腦模擬按快捷鍵時滑鼠需要放在網頁空白處,要改變chrome設定預設下載路徑,要把輸入法調成全英不然即使切換到英在對話方塊彈出來是還是中文輸入法...反正困難很多,一個個克服就是了,下面貼上全部程式碼:
import pyautogui import time import pandas as pd from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import ElementClickInterceptedException from time import sleep #讀取儲存了所有網址的csv website=pd.read_csv('website.csv',encoding='gbk') #啟動瀏覽器 path='C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe' from selenium.webdriver import Chrome driver = Chrome(path) #開始模擬下載 for i in range(i,len(website)+1): url=website.iloc[:,1][i] driver.get(url) #use exception here for x in range(0, 8): # try 8 times try: # msg.send() # put your logic here button = driver.find_element_by_class_name("display-block") button.click() str_error = None except (ElementClickInterceptedException,NoSuchElementException): sleep(1) else: break time.sleep(5) pyautogui.click() # open 'Save as...' to save html and assets pyautogui.hotkey('ctrl', 's') time.sleep(1) pyautogui.typewrite(website.iloc[:,0][i] + '.html') time.sleep(1) pyautogui.press ('enter') time.sleep(4)
上面的程式碼我用到了try和except還有多次sleep是因為網頁載入比較慢,一定要留出充分的時間,但即便是我重複了八次,還有一些沒有載入成功。這樣折騰了好幾天終於把這個任務完成了。
BONUS:電腦可以模擬我自動操作了,那我可不可以放手出門了呢?
答案是可以哦。
推薦向日葵遠端監控,在你的手機和電腦上安裝對應軟體,同時給電腦設定禁止睡眠,人在外面時想要看程式執行到哪一步時,就可以開啟手機遠端監控操作你的電腦哦。