Selenium實現互動式模擬瀏覽器行為
前面介紹了網路爬蟲對靜態頁面的抓取,但是在爬取網頁的時候會遇到各種各樣的情況,比如下拉選項和表單提交,這些都是用之前的方法解決不了的。在Python爬蟲中處理這種需要模擬使用者操作的情況最好的方法之一就是使用Selenium
。
1.Selenium介紹
Selenium
是ThoughtWorks公司的一個強大的開源Web功能測試工具系列,採用Javascript
來管理整個測試過程,包括讀入測試套件、執行測試和記錄測試結果。它採用Javascript
單元測試工具JSUnit
為核心,模擬真實使用者操作,包括瀏覽頁面、點選連結、輸入文字、提交表單、觸發滑鼠事件等等,並且能夠對頁面結果進行種種驗證。也就是說,只要在測試用例中把預期的使用者行為與結果都描述出來,我們就得到了一個可以自動化執行的功能測試套件。
當然,我們使用的是Selenium的2.0版本,也叫webdriver
安裝
pip install selenium
先寫一個簡單的小程式,讓webdriver運作起來
# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver
browser = webdriver.Chrome()
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.baidu.com']
start_urls = ['http://www.baidu.com/']
def start_requests (self):
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
def parse(self, response):
pass
這就是一個簡單的模擬開啟百度的程式,輸入scrapy crawl baidu
讓爬蟲跑起來
如果程式執行錯誤,瀏覽器沒有開啟,那麼應該是沒有裝 Chrome 瀏覽器或者 Chrome 驅動沒有配置在環境變數裡。下載驅動,然後將驅動檔案放在Python的路徑下就可以了。
Chrom驅動下載
2.互動介面的實現
1.觸發按鈕點選事件
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.baidu.com']
start_urls = ['http://www.baidu.com/']
def start_requests(self):
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
elem = browser.find_element_by_xpath('//*[@id="kw"]')
elem.send_keys("網路爬蟲") # 在輸入框輸入網路爬蟲
button = browser.find_element_by_xpath('//*[@id="su"]')
button.click() # 觸發按鈕
def parse(self, response):
pass
這樣瀏覽器就會幫我們自動搜尋想要的內容
2.webdriver查詢元素
單個元素:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element_by_id('q')
input_second = browser.find_element_by_css_selector('#q')
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first,input_second,input_third)
browser.close()
常用的查詢方法:
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
3.觸發拖拽事件
以runoob上一個網頁作為例子
現在我們要做的事情就是把右邊的框拖到相應區域去
from selenium import webdriver
from selenium.webdriver import ActionChains # 引入動作鏈
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.runoob.com']
def start_requests(self):
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult') # 切換到iframeResult框架
source = browser.find_element_by_css_selector('#draggable') # 找到被拖拽物件
target = browser.find_element_by_css_selector('#droppable') # 找到目標
actions = ActionChains(browser) # 宣告actions物件
actions.drag_and_drop(source, target)
actions.perform() # 執行動作
執行結果:
4.觸發下拉框
我們通常會遇到兩種下拉框,一種使用的是html的標籤select
,另一種是使用input
標籤做的假下拉框。
這是一個select的下拉選項,現在我們要做的事就是選中其中一個值
def start_requests(self):
browser = webdriver.Chrome()
url = 'http://sahitest.com/demo/selectTest.htm'
browser.get(url)
s1 = Select(browser.find_element_by_id('s1')) # 例項化Select
s1.select_by_value("50") #選取vlue為50的選項
sleep(5)
browser.quit()
5.頁面的前進後退
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')
browser.back() # 後退
time.sleep(1)
browser.forward() # 前進
browser.close()
6.新增訪問cooike
'''
前面部分程式碼用於填寫登入資訊並登入
'''
# 獲取cookie並通過json模組將dict轉化成str
dictCookies = self.browser.get_cookies()
jsonCookies = json.dumps(dictCookies)
# 登入完成後,將cookie儲存到本地檔案
with open('cookies.json', 'w') as f:
f.write(jsonCookies)
# 初次建立連線,隨後方可修改cookie
self.browser.get('http://xxxx.com')
# 刪除第一次建立連線時的cookie
self.browser.delete_all_cookies()
# 讀取登入時儲存到本地的cookie
with open('cookies.json', 'r', encoding='utf-8') as f:
listCookies = json.loads(f.read())
for cookie in listCookies:
self.browser.add_cookie({
'domain': '.xxxx.com', # 此處xxx.com前,需要帶點
'name': cookie['name'],
'value': cookie['value'],
'path': '/',
'expires': None
})
# 再次訪問頁面,便可實現免登陸訪問
self.browser.get('http://xxx.com')
7.等待
有時候網路不給力,我們就需要設定一個等待時間讓瀏覽器停一會兒,而Selenium的等待又分為隱式等待和顯示等待。
隱式等待
當使用了隱式等待執行測試的時候,如果 WebDriver沒有在 DOM中找到元素,將繼續等待,超出設定時間後則丟擲找不到元素的異常,
換句話說,當查詢元素或元素並沒有立即出現的時候,隱式等待將等待一段時間再查詢 DOM,預設的時間是0
browser = webdriver.Chrome()
browser.implicitly_wait(10)#等待十秒載入不出來就會丟擲異常,10秒內加載出來正常返回
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
顯式等待
指定一個等待條件,和一個最長等待時間,程式會判斷在等待時間內條件是否滿足,如果滿足則返回,如果不滿足會繼續等待,超過時間就會丟擲異常
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
wait = WebDriverWait(browser, 5)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)