此係列文章收錄在公眾號中:數據大宇宙 > 爬蟲-Selenium > py
轉發本文並私信我"python",即可獲得Python資料以及更多系列文章(持續更新的)
作為"數據玩家",如果手頭上沒有數據怎麼辦?當然是用代碼讓程序自動化採集數據,但是現在"爬蟲"不是那麼容易,其中最困難的即是突破網站各種反爬機制。本系列將全面講解 Python 中一個非常成熟的庫 —— selenium,並教會你如何使用它爬取網絡上所需的數據
自動化爬蟲雖然方便,但希望大家能顧及網站服務器的承受能力,不要高頻率訪問網站。並且千萬不要採集敏感數據!!否則很容易"從入門到入獄"
本系列大部分案例同時採用 selenium 與 pyppeteer 庫講解,並且有 Python 和 C# 2門語言的實現文章,詳細請到公眾號目錄中找到。
前言
使用 Selenium 控制瀏覽器進行頁面跳轉時,經常需要等待機制才能讓爬蟲繼續執行,這次我們來看看等待機制的流程,如何隨心所欲做出各種等待效果。
機制
想象一下如果是一個機器人幫你從網頁上查找某個信息,比較合理的流程是:
讓機器人每隔1秒到頁面上"按規則"找一下如果找到,則通知你如果找不到,下一秒繼續如果超過10秒都找不到,通知你Selenium 的等待機制同樣如此,而上述機制中唯一可以變化的就是"查找規則",這體現為 wait.until 的第一個參數接受一個"可調用對象"
終於得到你
這次案例的網頁是我簡單創建的,啟動網站服務如下(jupyter notebook 為例子):
現在用代碼對這個頁面採集,看看網頁內容結構。
用"開發者工具",查看元素的標籤:
現在用代碼控制 Selenium ,找上述的 div 標籤。
首先導入包:
<code>from selenium import webdriverimport selenium.webdriver.support.wait as WA/<code>
主要代碼如下:
<code>driver = webdriver.Chrome()driver.get('http://localhost:8081/web_sp/')wait = WA.WebDriverWait(driver, poll_frequency=0.5, timeout=10)ct = wait.until(lambda w: w.find_element_by_css_selector('div.content'))ct.text/<code>行4:定義 WebDriverWait第一個參數傳入 driver參數 poll_frequency=0.5 是每 0.5 秒執行一次查找參數 timeout=10 是 10 秒都沒有找到任何東西,就超時錯誤行5:調用 wait.until 方法,參數就一個,傳入一個"可調用對象"(此處是一個 lambda),wait 對象會每隔 0.5 秒執行一次這個方法css 選擇器 "div.content" 相當於 "div[class=content]"行6:打印一下找到的文本
現在執行這個代碼,如下:
大概 10 秒後,代碼執行結束,報了一個錯誤:
我們再次執行代碼,這次我們在頁面出來之後10秒內,點擊頁面上的按鈕:
等你 n 次
瞭解這個機制,我們可以很靈活定製屬於自己的查找條件。
這次,我希望可以等新增內容到達一定次數才繼續執行後續的操作。
首先,我們要知道一點,傳入 wait.until 的方法是有限制的,必須只有一個參數(此參數實際為 driver)。
但是,我們希望自定義函數能夠靈活一點,可以知道 css 選擇器 和 條件數量,比如:
<code>def finds_by_count(css_selector, num): pass/<code>
我們可以利用嵌套函數實現:
<code>def finds_by_count(css_selector, num): def finds_by_count_(wd): res = wd.find_elements_by_css_selector(css_selector) if len(res) >= num: return res return finds_by_count_/<code>行2到5:符合 wait.until 參數的函數(只有一個參數)行3:使用 find_elements_by_css_selector 查找元素,此時我們可以在"下級函數"中使用"上級函數"的參數 css_selector 。此方法不管是否找到元素,都會返回一個列表(沒有找到則為空列表)行4,5:一旦找到的數量高於等於指定數量,則把找到的列表返回即可。如果沒有找到,沒有執行 return ,相當於返回 none行7:最關鍵的代碼,這是"上級方法" finds_by_count 的返回語句,把"下級方法" finds_by_count_ 返回出去。注意只是返回 finds_by_count_ ,而沒有調用他(因為方法名字後面沒有括號)
現在,試試效果了,代碼如下:
<code>driver = webdriver.Chrome()driver.get('http://localhost:8081/web_sp/')wait = WA.WebDriverWait(driver, timeout=10)cts = wait.until(finds_by_count('div.content', 3))[c.text for c in cts]/<code>行5:wait.until 中調用"上級方法" finds_by_count ,等待 class 屬性為 content 的 div 標籤,出現3個為止
出來頁面後,如果快速點擊3下按鈕,就能看到結果:
總結
用代碼控制 selenium 最關鍵的功能就是"等待機制",我們可以用來檢測各種條件,讓代碼無縫執行。
接下來,將介紹更多等待機制的應用場景(比如中途需要賬號登錄等),敬請關注!!
私信我"python",獲取本系列文章所有相關資料和源碼