轉發本文並私信我"python",即可獲得Python資料以及更多系列文章(持續更新的)
作為"數據玩家",如果手頭上沒有數據怎麼辦?當然是用代碼讓程序自動化採集數據,但是現在"爬蟲"不是那麼容易,其中最困難的即是突破網站各種反爬機制。本系列將全面講解 Python 中一個非常成熟的庫 —— selenium,並教會你如何使用它爬取網絡上所需的數據
自動化爬蟲雖然方便,但希望大家能顧及網站伺服器的承受能力,不要高頻率訪問網站。並且千萬不要採集敏感數據!!否則很容易"從入門到入獄"
本系列大部分案例同時採用 selenium 與 pyppeteer 庫講解,並且有 Python 和 C# 2門語言的實現文章,詳細請到公眾號目錄中找到。
前言
學習任何一個庫,必須先了解這個庫的機制與流程,今天先從一個小例子開始我們的學習之旅。
搜索並採集結果的標題
需求如下:
打開百度搜索主頁在輸入框輸入搜索內容(比如"爬蟲")點擊"百度一下"按鈕,進行搜索把結果頁面中的第一頁的各個結果的主標題抓取下來Selenium 的麻煩之處
本系列始終圍繞一點開展:"用代碼操作瀏覽器",下面看看整個流程:
Python 代碼通過 selenium 庫,控制"瀏覽器驅動"程序(一個 exe 文件)"瀏覽器驅動"程序則發送指令操控"瀏覽器"但是,市面上存在各種瀏覽器,而且就算只是一個廠商的瀏覽器也有不同的版本。怎麼能保證我們的代碼只需要寫一次,就能控制不同的瀏覽器?
深入一點的流程圖如下:
不同廠商不同版本的瀏覽器,都需要一個對應版本的"瀏覽器驅動""怎麼案例都沒開始,就在說 selenium 的不是呢?我到底還學不學?"
他有如下優點:
selenium 庫已經開發很久,相對來說比較穩定selenium 在各個語言的庫都是有 google 開發維護,因此不會出有些問題只在 Python 版本出現selenium 相比 pyppeteer 容易學一些有一個 selenium-ide 工具,能夠把手工操作過程直接轉換為 selenium 的代碼缺點:
不同版本不同廠商的瀏覽器需要不同的驅動程序無法精細控制請求過程的各種處理,如下無法在執行網站 js 代碼之前,執行自己的 js 代碼無法在登錄階段控制瀏覽器讓人工登錄獲得 cookies,後續直接請求獲得數據如果你認為無法接受 selenium 的缺點,可以查看 pyppeteer 的相關文章
獲得驅動
現在讓我們來開始使用 selenium 解決我們的需求。
首先,使用pip安裝selenium
你可以在 jupyter notebook 的 cell 中執行 "!pip install selenium"也可以在 cmd 中執行 "pip install selenium"由於我本機安裝了GoogleChrome瀏覽器,打開瀏覽器,看看瀏覽器的版本:
版本為 78.0.3904.70接著到相關網站(私信我"python")下載對應的驅動:
點擊進入瀏覽器版本號對應的目錄
下載 win32 版本壓縮包解壓後,裡面有一個 chromedriver.exe ,這個就是"瀏覽器驅動"萬事俱備
看過我的相關教學文章的小夥伴都知道,我很喜歡從語義角度去理解學習一個庫。
selenium 本質上是控制瀏覽器,因此當我們使用它的時候,代碼的語義應該與手工操作瀏覽器的過程大同小異才合理。
首先導入一些包:
下面來看看怎麼用代碼來描述我們的手工操作。
打開瀏覽器:
行1:webdriver.Chrome() ,實例化一個 Chrome 對象,如果你是其他瀏覽器,那麼就要實例化對應瀏覽器的對象這代碼相當於我們手工啟動瀏覽器一樣但是,代碼報錯了。他的意思是,他找不到"瀏覽器驅動"的確,剛剛我們把驅動下載下來,但是 Python 怎麼可能會知道去哪裡找到那個驅動程序呢。
我們可以在實例化瀏覽器對象時,傳入一個文件路徑,告訴他程序的具體位置:
注意,要傳入完整的文件路徑我們也可以直接把"驅動程序"放置在代碼所在目錄此時可以看到瀏覽器被啟動,默認開啟一個空白頁面,並且下方出現一行文字說,"此瀏覽器被控制"輸入百度搜索的網址
:
行2:wd.get() ,傳入網址即可注意,每次重複執行 webdriver.Chrome() 都會啟動一個新的瀏覽器滑鼠移到輸入框,點擊一下,然後輸入內容"爬蟲":
這裡的問題是,怎麼用代碼表達"滑鼠移到輸入框,點擊一下"?
事實上,selenium 真可以模擬滑鼠移動等操作(有些網站的登錄驗證碼需要用滑鼠拉動拼圖都可以模擬),但是現在的情況我們不應該模擬滑鼠,而是根據 html 標籤定位即可。
此時我們使用瀏覽器的"開發者功能",進行定位即可。
由於篇幅關係,本文不詳細講解"開發者功能"的所有操作,詳細講解將放在:數據大宇宙 > 爬蟲工具 > 系列文章
也可以按快捷鍵 F12 啟動此功能(大部分瀏覽器都可以)下面用一個動態圖展示操作過程:
點擊功能區(右區)的左上角的小標籤,開啟定位模式此時滑鼠移到頁面區(左區),滑鼠移到的地方,右區會顯示此元素在 html 的位置我們看到,輸入框是一個 input 標籤,我們要在代碼中告訴 selenium 找到這個 input 標籤即可那麼用啥"暗號"表示這個 input 標籤呢?有2種常見的方式,css 選擇器 或者 xpathselenium 文檔中強烈推薦你使用 css 選擇器我們選用 css 選擇器,因此,在右區的 input 標籤上,按滑鼠右鍵,選 "copy" ,然後選擇"copy selector" ,此時已經把"暗號"複製到剪切板上看看代碼:
行3:wd.find_element_by_css_selector ,使用 css 選擇器找到元素,方法中傳入剛剛複製的"暗號"(按 ctor + v ,粘貼即可)。注意是字符串,因此要用單引號包圍此時,變量 input_box 則表示輸入框接著,
輸入內容"爬蟲"
:
行4:input_box.send_keys ,往該元素髮送按鍵,這個方法不僅僅能發送鍵盤的按鍵,還能往可輸入的元素髮送文本此時可以看到,瀏覽器已經輸入了內容"爬蟲",並且還可以看到下方已經出現搜索結果(這是因為現在的搜尋引擎都提供這種邊輸入邊查詢的功能)我們繼續模擬點擊輸入框右邊的"百度一下"這個按鈕。
同樣用"開發者功能",定位該元素,並複製css選擇器表達字符串:
行7:用 css 選擇器找到按鈕行8:act_btn.click() 方法,對元素模擬點擊現在瀏覽器顯示的頁面,就有我們需要的所有的內容所有結果的主標題:
這個可能對初學者有點難度,因為我們這次需要一次選擇多個元素(多個搜索結果的主標題),看看定位到的標籤:
每個搜索結果,都是一個 div標籤(上圖右區下方紅框)而所有的搜索結果的 div,都被包在一個 id='content_left' 的 div 標籤裡面(上圖右區上方紅框)進一步看看我們需要的主標題在哪裡:
我們要的數據都在一個 a 標籤下並且這個 a 標籤被放在一個 h3 標籤裡面那麼,現在我們要用 css 選擇器表達以下語義:在一個div(id=content_left)裡面,h3 標籤裡面的 a 標籤的文本。div 與 h3 之間可能嵌套了多層。
得到的選擇器表達式如下:
div[id=content_left] 表示 div 標籤,他的 id 屬性為 content_leftdiv 與 h3 之間用空格分開,表示他們是祖孫關係,就是 div 與 h3 之間有其他任意多的其他標籤嵌套h3 與 a 之間,用">" 分開,表示父子關係,就是 a 標籤就是在 h3 標籤包圍調用代碼如下:
行10:wd.find_elements_by_css_selector ,查找符合選擇器的多個元素,注意方法名字的單詞 elements 是複數的,與 行4 和 行7 的方法是不一樣此時,titles 其實是一個列表,裡面全是符合條件的 a 標籤,但是我們的目標是 a 標籤裡面的文本行11:調用 a 標籤的文本屬性,獲得其文本但是,你會發現結果啥也沒有!!!代碼執行太快了
上面的代碼之所以拿不到任何結果,是因為當執行到第10行的代碼時,頁面上還沒有加載任何的結果。
如果是一個人在操作瀏覽器,那麼你應該跟他說:嘿,一直到你看到那些結果,你再去提取主標題啊。
怎麼表達"一直到你看到那些結果"?,selenium有專門用於等待元素出現的機制,代碼如下:
行10:實例化一個 WebDriverWait 對象,注意在一開始導入包的時候,我們導入了 import selenium.webdriver.support.wait as WA行11:調用 wait.until 方法,傳入 lambda ,selenium 會定時執行裡面的方法,直到裡面的方法有返回對象此時可以見到,我們得到了結果關於更多等待機制的知識點,請關注本系列後續的文章加上關閉瀏覽器的控制,完整代碼如下:
總結
用代碼控制 selenium 基本與人工操作一致,一般的流程:
啟動瀏覽器定位元素(必要時要等元素出現)操作元素(點擊或其他)不斷進行定位與操作過程,直到出現目標頁面,爬取數據即可下一節,將介紹更多 selenium 的技巧,敬請關注!!
私信我"python",獲取本系列文章所有相關資料和源碼