Python?爬蟲利器?Selenium?從入門到進(jìn)階
來源 | 關(guān)于數(shù)據(jù)分析與可視化今天小編就來講講
selenium
,我們大致會(huì)講這些內(nèi)容selenium
簡(jiǎn)介與安裝- 頁面元素的定位
- 瀏覽器的控制
- 鼠標(biāo)的控制
- 鍵盤的控制
- 設(shè)置元素的等待
- 獲取
cookies
- 調(diào)用
JavaScript
selenium
進(jìn)階
selenium
的簡(jiǎn)介與安裝
selenium
是最廣泛使用的開源Web UI自動(dòng)化測(cè)試套件之一,它所支持的語言包括C
、Java
、Perl
、PHP
、Python
和Ruby
,在數(shù)據(jù)抓取方面也是一把利器,能夠解決大部分網(wǎng)頁的反爬措施,當(dāng)然它也并非是萬能的,一個(gè)比較明顯的一點(diǎn)就在于是它速度比較慢,如果每天數(shù)據(jù)采集的量并不是很高,倒是可以使用這個(gè)框架。那么說到安裝,可以直接使用pip
在安裝pip?install?selenium與此同時(shí)呢,我們還需要安裝一個(gè)瀏覽器驅(qū)動(dòng),不同的瀏覽器需要安裝不同的驅(qū)動(dòng),這邊小編主要推薦的以下這兩個(gè)
Firefox
瀏覽器驅(qū)動(dòng):geckodriver
Chrome
瀏覽器驅(qū)動(dòng):chromedriver
selenium
chromedriver
比較多,所以這里就以Chrome
瀏覽器為示例,由于要涉及到chromedriver
的版本需要和瀏覽器的版本一致,因此我們先來確認(rèn)一下瀏覽器的版本是多少?看下圖我們?cè)凇瓣P(guān)于Chrome”當(dāng)中找到瀏覽器的版本,然后下載對(duì)應(yīng)版本的chromedriver
,當(dāng)然也要對(duì)應(yīng)自己電腦的操作系統(tǒng)頁面元素的定位
在談到頁面元素的定位時(shí),小編默認(rèn)讀者朋友具備了最最基本的前端知識(shí),例如HTML
,CSS
等ID標(biāo)簽的定位
在HTML
當(dāng)中,ID屬性是唯一標(biāo)識(shí)一個(gè)元素的屬性,因此在selenium
當(dāng)中,通過ID來進(jìn)行元素的定位也作為首選,我們以百度首頁為例,搜索框的HTML
代碼如下,其ID為“kw”,而“百度一下”這個(gè)按鈕的ID為“su”,我們用Python
腳本通過ID的標(biāo)簽來進(jìn)行元素的定位driver.find_element_by_id("kw")driver.find_element_by_id("su")
NAME標(biāo)簽的定位
在HTML
當(dāng)中,Name屬性和ID屬性的功能基本相同,只是Name屬性并不是唯一的,如果遇到?jīng)]有ID標(biāo)簽的時(shí)候,我們可以考慮通過Name標(biāo)簽來進(jìn)行定位,代碼如下driver.find_element_by_name("wd")Xpath定位
使用Xpath
方式來定位幾乎涵蓋了頁面上的任意元素,那什么是Xpath
呢?Xpath
是一種在XML
和HTML
文檔中查找信息的語言,當(dāng)然通過Xpath
路徑來定位元素的時(shí)候也是分絕對(duì)路徑和相對(duì)路徑。絕對(duì)路徑是以單號(hào)/
來表示,相對(duì)路徑是以//
來表示,而涉及到Xpath
路徑的編寫,小編這里偷個(gè)懶,直接選擇復(fù)制/粘貼的方式,例如針對(duì)下面的HTML
代碼"en">
????"UTF-8">
????Test
我們可以這么來做,打開瀏覽器的開發(fā)者工具,鼠標(biāo)移到我們選中的元素,然后右擊檢查,具體看下圖我們還是以百度首頁為例,看一下如何通過
Xpath
來進(jìn)行頁面元素的定位,代碼如下driver.find_element_by_xpath('//*[@id="kw"]')className標(biāo)簽定位
我們也可以基于class
屬性來定位元素,尤其是當(dāng)我們看到有多個(gè)并列的元素如list
表單,class
用的都是共用同一個(gè),如:driver.find_element_by_class_name("classname")這個(gè)時(shí)候,我們就可以通過
class
屬性來定位元素,該方法返回的是一個(gè)list
列表,而當(dāng)我們想要定位列表當(dāng)中的第n個(gè)元素時(shí),則可以這樣來安排driver.find_elements_by_class_name("classname")[n]需要注意的是,這里使用的是
find_elements_by_class_name()
方法而不是find_element_by_class_name()
方法,這里我們還是通過百度首頁的例子,通過className
標(biāo)簽來定位搜索框這個(gè)元素driver.find_element_by_class_name('s_ipt')CssSelector()
方法定位
其實(shí)在Selenium
官網(wǎng)當(dāng)中是更加推薦CssSelector()
方法來進(jìn)行頁面元素的定位的,原因在于相比較于Xpath
定位速度更快,Css
定位分為四類:ID值、Class
屬性、TagName
值等等,我們依次來看- ID方式來定位
TagName
的值,另外一種則是不加,代碼如下driver.find_element_by_css_selector("#id_value")??#?不添加前面的`TagName`值driver.find_element_by_css_selector("tag_name.class_value")??#?不添加前面的`TagName`值
當(dāng)然有時(shí)候這個(gè)
TagName
的值非常的冗長(zhǎng),中間可能還有空格,那么這當(dāng)中的空格就需要用點(diǎn)“.”來替換driver.find_element_by_css_selector("tag_name.class_value1.calss_value2.class_value3")??#?不添加前面的`TagName`值我們?nèi)匀灰园俣仁醉摰乃阉骺驗(yàn)槔?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(150, 84, 181);">HTML代碼如下要是用
CssSelector
的.class()
方式來實(shí)現(xiàn)元素的定位的話,Python
代碼該這樣來實(shí)現(xiàn),和上面Xpath()
的方法一樣,可以稍微偷點(diǎn)懶,通過復(fù)制/粘貼的方式從開發(fā)者工具當(dāng)中來獲取元素的位置代碼如下driver.find_element_by_css_selector('#kw')linkText()方式來定位
這個(gè)方法直接通過鏈接上面的文字來定位元素,案例如下通過linkText()
方法來定位“地圖”這個(gè)元素,代碼如下driver.find_element_by_link_text("地圖").click()瀏覽器的控制
修改瀏覽器窗口的大小
我們可以通過使用set_window_size()
這個(gè)方法來修改瀏覽器窗口的大小,代碼如下#?修改瀏覽器的大小driver.set_window_size(500,?900)
同時(shí)還有
maxmize_window()
方法是用來實(shí)現(xiàn)瀏覽器全屏顯示,代碼如下#?全屏顯示driver.maximize_window()
瀏覽器的前進(jìn)與后退
前進(jìn)與后退用到的方法分別是forward()
和back()
,代碼如下#?前進(jìn)與后退driver.forward()
driver.back()
瀏覽器的刷新
刷新用到的方法是refresh()
,代碼如下#?刷新頁面driver.refresh()
除了上面這些,
webdriver
的常見操作還有- 關(guān)閉瀏覽器:
get()
- 清除文本:
clear()
- 單擊元素:
click()
- 提交表單:
submit()
- 模擬輸入內(nèi)容:
send_keys()
from?time?import?sleep
driver?=?webdriver.Chrome(executable_path="chromedriver.exe")
driver.get("https://www.baidu.com")
sleep(3)
driver.maximize_window()
sleep(1)
driver.find_element_by_xpath('//*[@id="s-top-loginbtn"]').click()
sleep(3)
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_11__userName"]').send_keys('12121212')
sleep(1)
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_11__password"]').send_keys('testtest')
sleep(2)
driver.refresh()
sleep(3)
driver.quit()
output
鼠標(biāo)的控制
鼠標(biāo)的控制都是封裝在ActionChains
類當(dāng)中,常見的有以下幾種引入action_chains類from?selenium.webdriver.common.action_chains?import?ActionChains
#?右擊
ActionChains(driver).context_click(element).perform()
#?雙擊
ActionChains(driver).double_click(element).perform()
#?拖放
ActionChains(driver).drag_and_drop(Start,?End).perform()
#?懸停
ActionChains(driver).move_to_element(Above).perform()
#?按下
ActionChains(driver).click_and_hold(leftclick).perform()
#?執(zhí)行指定的操作
鍵盤的控制
webdriver
中的Keys()
類,提供了幾乎所有按鍵的方法,常用的如下#?刪除鍵driver.find_element_by_id('xxx').send_keys(Keys.BACK_SPACE)
#?空格鍵
driver.find_element_by_id('xxx').send_keys(Keys.SPACE)
#?回車鍵
driver.find_element_by_id('xxx').send_keys(Keys.ENTER)
#?Ctrl? ?A?全選內(nèi)容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL,?'a')
#?Ctrl? ?C/V?復(fù)制/粘貼內(nèi)容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL,?'c')
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL,?'v')
其他的一些鍵盤操作
- 向上箭頭:
Keys.ARROW_UP
- 向下箭頭:
Keys.ARROW_DOWN
- 向左/向右箭頭:
Keys.ARROW_LEFT
/Keys.ARROW_RIGHT
- Shift鍵:
Keys.SHIFT
- F1鍵:
Keys.F1
元素的等待
有顯示等待和隱式等待兩種顯示等待
顯示等待指的是設(shè)置一個(gè)超時(shí)時(shí)間,每隔一段時(shí)間去查看一下該元素是否存在,如果存在則執(zhí)行后面的內(nèi)容,要是超過了最長(zhǎng)的等待時(shí)間,則拋出異常(TimeoutException
),需要用到的是WebDriverWait()
方法,同時(shí)配合until
和not until
方法WebDriverWait(driver,?timeout,?poll_frequency=0.5,?ignored_exceptions=None)其中的參數(shù):
- timeout: 最長(zhǎng)超時(shí)時(shí)間,默認(rèn)以秒為單位
- poll_frequency: 檢測(cè)的時(shí)間間隔,默認(rèn)是0.5s
- ignored_exceptions: 指定忽略的異常,默認(rèn)忽略的有
NoSuchElementException
這個(gè)異常
driver.get("http://somedomain/url_that_delays_loading")
try:????
????element?=?WebDriverWait(driver,?10).until(???????????
????????EC.presence_of_element_located((By.ID,?"myDynamicElement")))
finally:????
????driver.quit()
上面的代碼最多等待10秒,超時(shí)后就拋出異常,但是假設(shè)在等了3秒之后就找到了這個(gè)元素,那么也就不會(huì)多等下剩下的7秒鐘時(shí)間,而是繼續(xù)執(zhí)行后續(xù)的代碼
隱式等待
主要使用的是implicitly_wait()
來實(shí)現(xiàn)browser?=?webdriver.Chrome(path)#?隱式等待3秒
browser.implicitly_wait(3)
獲取Cookie
Cookie
是用來識(shí)別用戶身份的關(guān)鍵,我們通常也是通過selenium
先模擬登錄網(wǎng)頁獲取Cookie
,然后再通過requests
攜帶Cookie
來發(fā)送請(qǐng)求。webdriver
提供了cookies
的幾種操作,我們挑選幾個(gè)常用的來說明get_cookies()
:以字典的形式返回當(dāng)前會(huì)話中可見的cookie
信息get_cookies(name)
: 返回cookie
字典中指定的的cookie
信息add_cookie(cookie_dict)
: 將cookie
添加到當(dāng)前會(huì)話中
driver.get(url=url)
time.sleep(1)
cookie_list=driver.get_cookies()
cookies?=";".join([item["name"]? "="? ?item["value"]? ?""?for?item?in?cookie_list])
session=requests.session()
headers?=?{
????'User-Agent':'Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/83.0.4103.106?Safari/537.36',
????'cookie':?cookies
}
response=session.get(url=url,headers=headers)
soup=BeautifulSoup(response.text,'lxml')
調(diào)用JavaScript
在webdriver
當(dāng)中可以使用execut_script()
方法來實(shí)現(xiàn)JavaScript
的執(zhí)行,下面我們來看一個(gè)簡(jiǎn)單的例子from?selenium?import?webdriverimport?time
bro=webdriver.Chrome(executable_path='./chromedriver')
bro.get("https://www.baidu.com")
#?執(zhí)行js代碼
bro.execute_script('alert(10)')
time.sleep(3)
bro.close()
除此之外,我們還可以通過
selenium
執(zhí)行JavaScript
來實(shí)現(xiàn)屏幕上下滾動(dòng)from?selenium?import?webdriverbro=webdriver.Chrome(executable_path='./chromedriver')
bro.get("https://www.baidu.com")
#?執(zhí)行js代碼
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
selenium
進(jìn)階
selenium
啟動(dòng)的瀏覽器,會(huì)非常容易的被檢測(cè)出來,通常可以通過window.navigator.webdriver
的值來查看,如果是true
則說明是使用了selenium
模擬瀏覽器,如果是undefined
則通常會(huì)被認(rèn)為是正常的瀏覽器。那么我們似乎可以執(zhí)行下面這段代碼來強(qiáng)行更改window.navigator.webdriver
最后返回的值driver.execute_script(????'Object.defineProperties(navigator,{webdriver:{get:()=>false}})'
)
當(dāng)然這種方法也有一定的缺陷,畢竟這段代碼是在網(wǎng)頁已經(jīng)加載完畢之后才運(yùn)行的,此時(shí)網(wǎng)頁自身的
JavaScript
程序已經(jīng)通過讀取window.navigator.webdriver
知道你使用的是模擬瀏覽器了。所以我們有兩種辦法來解決這個(gè)缺陷。- 在Chrome當(dāng)中添加實(shí)驗(yàn)性功能參數(shù)
from?selenium.webdriver?import?ChromeOptions
option?=?ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
driver=Chrome(options=option)
- 調(diào)用chrome當(dāng)中的開發(fā)工具協(xié)議的命令
Chrome
瀏覽器在打開頁面,還沒有運(yùn)行網(wǎng)頁自帶的JavaScript
代碼時(shí),先來執(zhí)行我們給定的代碼,通過execute_cdp_cmd()
方法,driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",?{????"source":?"""
????????Object.defineProperty(navigator,?'webdriver',?{
????????????get:?()?=>?undefined
????????})
????"""
})
當(dāng)然為了更好隱藏指紋特征,我們可以將上面兩種方法想結(jié)合from?selenium?import?webdriver
options?=?webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches",?["enable-automation"])
options.add_experimental_option('useAutomationExtension',?False)
driver?=?webdriver.Chrome(options=options,?executable_path='./chromedriver')
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",?{
??"source":?"""
????Object.defineProperty(navigator,?'webdriver',?{
??????get:?()?=>?undefined
????})
??"""
})
driver.get(url)
最后的最后,我們也可以通過運(yùn)行
stealth.min.js
文件來實(shí)現(xiàn)隱藏selenium
模擬瀏覽器的特征,這個(gè)文件之前是給puppeteer
用的,使得其隱藏瀏覽器的指紋特征,而讓Python
使用時(shí),需要先導(dǎo)入這份JS
文件import?timefrom?selenium.webdriver?import?Chrome
option?=?webdriver.ChromeOptions()
option.add_argument("--headless")
#?無頭瀏覽器需要添加user-agent來隱藏特征
option.add_argument('user-agent=.....')
driver?=?Chrome(options=option)
driver.implicitly_wait(5)
with?open('stealth.min.js')?as?f:
????js?=?f.read()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",?{
??"source":?js
})
driver.get(url)
往期回顧資訊程序員敲詐老板,或面臨37年監(jiān)禁資訊
Meta新語音模型可支持128種語言交流資訊全球首個(gè)活體機(jī)器人,能生娃專訪低代碼平臺(tái)產(chǎn)品的使用者都是誰?
分享點(diǎn)收藏點(diǎn)點(diǎn)贊點(diǎn)在看