第六章 selenium自動化測試工具:天下工具爲我所用

在這裏插入圖片描述

簡介

Selenium是一個Web的自動化測試工具,類型像我們玩遊戲用的按鍵精靈,它支持所有主流的瀏覽器(包括PhantomJS這些無界面的瀏覽器)。

Selenium 可以根據我們的指令,讓瀏覽器自動加載頁面,獲取需要的數據,甚至頁面截屏,或者判斷網站上某些動作是否發生。

但是被用歪了,現在一般作爲破解反爬的一種手段,一般用於解決動態頁面或者js加密的爬蟲問題。(ps:只要有js參與頁面動態生成元素的都叫動態頁面)

不然的話用Python 解決這個問題只有兩種途徑:
1.直接從JavaScript 代碼裏採集內容(費時費力)
2.用Python 的第三方庫運行JavaScript,直接採集你在瀏覽器裏看到的頁面。

案例瓜子二手手網站爬取:
import requests

headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
}
html = requests.get("https://www.guazi.com/zz/?ca_s=pz_baidu&ca_n=tbmkbturl&scode=10103000312",headers=headers).content.decode()
print(html)

結果:
<!DOCTYPE html>
        <html lang="en">
            <head>
                <meta charset="utf-8">
                <script type="text/javascript">...</script>
            </head>
            <body>
            <p>正在打開中,請稍後...<e style='float:right'>2019-05-30 17:36:20</e><p>
            </body>
        </html>



用今天的技術就可以解決:
from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://www.guazi.com/zz/?ca_s=pz_baidu&ca_n=tbmkbturl&scode=10103000312")
print(driver.page_source)

結果:很OK

安裝

pip install selenium==3.8.0 爲了適配phantomjs

如果不適配phantomjs 直接pip install selenium

或者可以使用清華源,安裝更快
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple selenium

瀏覽器驅動的安裝

Selenium 自己不帶瀏覽器,需要自己安裝瀏覽器軟件和驅動
一般測試階段使用帶界面的瀏覽器(谷歌/火狐等):

1.谷歌瀏覽器下載配置:

打開如下頁面:http://npm.taobao.org/mirrors/chromedriver/
把exe文件放置到自己的python環境安裝目錄

2.火狐瀏覽器下載配置:

打開如下頁面:https://github.com/mozilla/geckodriver/releases

把exe文件放置到自己的python環境安裝目錄

3.phantomjs瀏覽器下載配置:

官網下載安裝http://phantomjs.org/download.html
1、解壓放到:C:\phantomjs-2.1.1-windows
2、需設置環境變量,Path添加C:\phantomjs-2.1.1-windows\bin

問題說明:

真正生成環境下爬取數據階段使用無界面(PhantomJS)
但是谷歌火狐也可以設置爲無頭瀏覽器

最新版本的selenium3.11.0停止對PhantomJS的支持,需要對selenium降級
pip3 install selenium==3.8.0

有時就算這裏設置環境變量,後邊有可能程序運行的時候,也有可能發生找不到的情況發生
沒關係我們可以直接在代碼裏可以設置指明路徑
webdriver.PhantomJS(executable_path=“安裝路徑”)

知識

快速入門

Selenium 庫裏有個叫WebDriver 的API。WebDriver可以加載網站也可以查找頁面元素,對頁面上的元素進行交互(發送文本、點擊等),以及執行其他動作來運行網絡爬蟲。

from selenium import webdriver
import time

# 打開瀏覽器驅動
driver = webdriver.Firefox()

# 加載網址
driver.get("http://www.baidu.com")

# 頁面源碼
print(driver.page_source)

# 獲取 cookie
print(driver.get_cookies())

# url
print(driver.current_url)

# 截圖
driver.save_screenshot("./baidu0.png")

# 輸入
driver.find_element_by_id("kw").send_keys("996")
time.sleep(2)

# 截圖
driver.save_screenshot("./baidu1.png")

# 點擊
driver.find_element_by_id("su").click()
time.sleep(2)

# 截圖
driver.save_screenshot("./baidu2.png")

# 退出
driver.quit()

定位UI元素(WebElements)

各種方式獲取元素

單個元素查找 search

# 通過屬性爲name的值進行過濾
find_element_by_name
find_element_by_id
find_element_by_tag_name
find_element_by_class_name

# 通過鏈接的文本進行過濾
find_element_by_link_text
# 通過鏈接的部分文本進行過濾
find_element_by_partial_link_text

# 通過xpath查找
find_element_by_xpath
# 通過css選擇器查找
find_element_by_css_selector

多個元素查找 findall
find_elements_by_name
find_elements_by_id
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector


通過find_element + by的屬性實現獲取元素
from selenium.webdriver.common.by import By

setfElement = driver.find_element(By.ID,"setf")

獲取元素屬性值

元素.get_attribute('屬性名')

from selenium import webdriver

# 打開瀏覽器
browser = webdriver.Chrome()
# 發送請求
url = 'https://www.zhihu.com/explore'
browser.get(url)
# 查找元素
logo =browser.find_element_by_id('zh-top-link-logo')
print(logo)
# 獲取元素屬性
print(logo.get_attribute('class'))

獲取元素標籤內部值

元素.text

from selenium import webdriver

# 打開瀏覽器
browser = webdriver.Chrome()
# 發送請求
url = 'https://www.zhihu.com/explore'
browser.get(url)
# 查找元素
input = browser.find_element_by_class_name('zu-top-add-question')
# 獲取元素文本值
print(input.text)

一些瑣碎的知識點

執行JavaScript

# 執行js腳本
driver = webdriver.Firefox()
driver.get("https://www.jd.com/")
sleep(2)
# 窗口滑動到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
sleep(2)
driver.quit()

截圖

使用不同的瀏覽器即可
PhantomJS是長截圖
火狐谷歌是短截圖

# 長截圖短截圖
# 短的
driver = webdriver.Firefox()
driver.get("http://www.moguproxy.com/http")
sleep(2)
driver.save_screenshot("./短截圖.png")
driver.quit()

# 長的
driver = webdriver.PhantomJS()
driver.get("http://www.moguproxy.com/http")
sleep(2)
driver.save_screenshot("./長截圖.png")
driver.quit()

窗口最大化

# 瀏覽器對象.maximize_window

driver.maximize_window()

元素的位置大小屬性(用於截圖)

電腦分辨率和縮放比例的改變會影響屬性值,用於後邊的截圖搞驗證碼

from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
# 瀏覽器窗口最大化
driver.maximize_window()
sleep(2)
driver.save_screenshot("./baiduLogo.png")
logoElement = driver.find_element_by_id("kw")
# 唯一id 指向某一個元素
print(logoElement.id)
# 標籤名
print(logoElement.tag_name)
# 元素座標位置
print(logoElement.location)
# 本身元素大小(受電腦本身屏幕分辨率和文本縮放比例有關係)
print(logoElement.size)
sleep(2)
driver.quit()

動作鏈

動作鏈(模擬用戶行爲)

點擊

from selenium import webdriver
from time import sleep
# 比較長 導入動作鏈類
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/clicks.htm")
sleep(2)

# 找到需要操作的元素
dbclickElement = driver.find_element_by_xpath("//input[contains(@value,'dbl click me')]")
leftclickElement = driver.find_element_by_xpath("//input[@value='click me']")
rightclickElement = driver.find_element_by_xpath("//input[contains(@value,'right click me')]")

# 鏈式寫法
# 傳入瀏覽器對象構造動作鏈
actionChains = ActionChains(driver)
# 調用各種各樣的動作函數 
# double_click左鍵雙擊一個元素   
# click左鍵單擊一個元素
# context_click右鍵單擊一個元素


actionChains.double_click(dbclickElement).click(leftclickElement).context_click(rightclickElement).perform()


# 或者分開寫
# 傳入瀏覽器對象構造動作鏈
actionChains = ActionChains(driver)
# 左鍵雙擊一個元素
actionChains.double_click(dbclickElement)
# 執行 不要忘記
actionChains.perform()

sleep(2)

actionChains = ActionChains(driver)
# 左鍵單擊一個元素
actionChains.click(leftclickElement)
actionChains.perform()
sleep(2)

actionChains = ActionChains(driver)
# 右鍵單擊一個元素
actionChains.context_click(rightclickElement)
actionChains.perform()
sleep(2)

移動

from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/mouseover.htm")
sleep(3)

# 找到需要鼠標移動指向的元素
hiElement = driver.find_element_by_xpath("//span[contains(.,'Hi Kamlesh')]")
writeElement = driver.find_element_by_xpath("//input[@value='Write on hover']")
blankElement = driver.find_element_by_xpath("//input[@value='Blank on hover']")

# 直接移動到某一個元素
ActionChains(driver).move_to_element(hiElement).perform()
sleep(2)

# 在當前位置移動x,y的偏移
ActionChains(driver).move_by_offset(10,25).perform()
sleep(2)

# 先移動到某一個元素 再做偏移 是上面兩個api的封裝
ActionChains(driver).move_to_element_with_offset(writeElement,5,55).perform()
sleep(5)

driver.quit()

拖拽

from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/dragDropMooTools.htm")
driver.maximize_window()
sleep(5)
driver.save_screenshot("./dragMe.png")

# 找到相關需要拖拽的元素
dragMe = driver.find_element_by_xpath("//div[@class='drag']")
item1 = driver.find_element_by_xpath("//div[contains(.,'Item 1')]")
item2= driver.find_element_by_xpath("//div[contains(.,'Item 2')]")
item3 = driver.find_element_by_xpath("//div[contains(.,'Item 3')]")
item4 = driver.find_element_by_xpath("//div[contains(.,'Item 4')]")

# drag_and_drop 拖某一個到某一個元素
ActionChains(driver).drag_and_drop(dragMe,item1).perform()
sleep(2)
# drag_and_drop_by_offset 按當前鼠標的位置的偏移 拖拽一個元素
ActionChains(driver).drag_and_drop_by_offset(dragMe,190,250).perform()
sleep(2)
# click_and_hold 鼠標左鍵持續按住一個元素 move_to_element 移動到某一個元素
# release 釋放鼠標
ActionChains(driver).click_and_hold(dragMe).move_to_element(item3).release().perform()
sleep(2)
# click_and_hold 鼠標左鍵持續按住一個元素
# move_to_element_with_offset 移動到某一個元素再偏移一定像素
# release 釋放鼠標
ActionChains(driver).click_and_hold(dragMe).move_to_element_with_offset(item3,150,10).release().perform()
sleep(2)

driver.quit()

按鍵

from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/keypress.htm")
sleep(3)

# 找到相關元素
enter = driver.find_element_by_xpath("//input[@name='t2']")
keyUp = driver.find_element_by_xpath("//label[contains(.,'Key Up')]")
keyDown = driver.find_element_by_xpath("//label[contains(.,'Key Down')]")
keyPress = driver.find_element_by_xpath("//label[contains(.,'Key Press')]")

# 按鍵週期 按下-按住-擡起 操作邏輯必須符合按鍵週期

# 按鍵擡起測試
ActionChains(driver).click(keyUp).click(enter).key_down("a",enter).key_up("a").perform()
sleep(2)


# 按鍵按下測試
keyDown.click()
enter.click()
ActionChains(driver).key_down("s",enter).key_up("s").perform()
sleep(2)


# 持續按住測試
keyPress.click()
enter.click()
ActionChains(driver).key_down("d",enter).key_up("d").perform()
sleep(2)

driver.quit()

下拉框

from selenium import webdriver
from time import sleep
# 導入一個下拉框類
from selenium.webdriver.support.ui import Select

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/selectTest.htm")
sleep(3)

# 下拉框操作 需要提前構造 Select類 參數:select標籤元素
select = Select(driver.find_element_by_xpath("//select[@id='s1Id']"))



# 按下標選 0-空 1,2,3-選項順序
select.select_by_index(1)
# 選擇的第一個 元素
print(select.first_selected_option.text)

sleep(2)

# 通過屬性value選擇
select.select_by_value("o2")
# 所有的選擇元素對象
for e in select.all_selected_options:
    print(e.text)
sleep(2)

# 按文本顯示內容
select.select_by_visible_text("o3")
print(select.first_selected_option.text)

sleep(2)
driver.quit()

各種切換

彈窗處理

switch_to_alert    切換到彈窗
accept                 點擊【確認】按鈕
dismiss                點擊【取消】按鈕(如有按鈕)
send_keys            輸入內容(如有輸入框)


from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/alertTest.htm")
sleep(3)

clickForAlert = driver.find_element_by_xpath("//input[@name='b1']")
# 觸發彈窗
clickForAlert.click()
sleep(1)


# 切換操作對象
alert = driver.switch_to_alert()
sleep(1)
alert.accept()
sleep(1)
driver.quit()

iframe定位

from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/iframesTest.htm")

print(driver.page_source)
print("===================================")
iframe = driver.find_element_by_tag_name("iframe")
# 查找到內嵌網頁iframe 切換
driver.switch_to_frame(iframe)
print(driver.page_source)

標籤操作

頁面切換

from selenium import webdriver
from time import sleep


driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
sleep(3)
# 當前瀏覽器的標籤集合
print(len(driver.window_handles))
print(driver.window_handles)
print("=============================================")
sleep(2)

driver.execute_script("window.open()")
driver.switch_to_window(driver.window_handles[1])
driver.get("http://www.pinduoduo.com")
print(len(driver.window_handles))
print(driver.window_handles)
print("=============================================")
sleep(2)

driver.execute_script("window.open()")
driver.switch_to_window(driver.window_handles[2])
driver.get("http://www.taobao.com")
sleep(2)

driver.switch_to_window(driver.window_handles[1])
sleep(2)

driver.switch_to_window(driver.window_handles[0])
sleep(2)

driver.close()
driver.quit()

頁面前進後退

from selenium import webdriver
from time import sleep


# 單個標籤的操作前進forward 後退back
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
sleep(3)
driver.find_element_by_xpath("//a[@name='tj_trnews']").click()
sleep(2)
driver.find_element_by_xpath("//a[@href='http://image.baidu.com/'][contains(.,'圖片')]").click()
sleep(2)
driver.back()
sleep(2)
driver.back()
sleep(2)
driver.forward()
sleep(2)
driver.forward()
sleep(2)
driver.close()

頁面滾動

# 執行js腳本
driver = webdriver.Firefox()
driver.get("https://www.jd.com/")
sleep(2)
# 窗口滑動到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
sleep(2)
driver.quit()

頁面刷新與關閉

# 頁面刷新
driver.flush()
# 關閉當前頁面 如是是最後一個標籤 關閉瀏覽器
driver.close()
# 直接關閉瀏覽器	
driver.quit()

頁面等待

強制等待

time.sleep

隱式等待

隱式等待比較簡單,就是簡單地設置一個等待時間,單位爲秒

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement= driver.find_element_by_id("myDynamicElement")
當然如果不設置,默認等待時間爲0。

顯示等待

顯式等待指定某個條件,然後設置最長等待時間。如果在這個時間還沒有找到元素,那麼便會拋出異常了。

from selenium import webdriver
from time import sleep

# expected_conditions 類,負責條件觸發
from selenium.webdriver.support import expected_conditions as EC
# WebDriverWait 庫,負責循環等待
from selenium.webdriver.support.ui import WebDriverWait
# 查找方式的庫
from selenium.webdriver.common.by import By

driver = webdriver.Firefox()
driver.get("http://sahitest.com/demo/linkTest.htm")

WebDriverWait(driver,30).until(EC.presence_of_element_located((By.XPATH,'//div[@class="WB_feed WB_feed_v3 WB_feed_v4"]')))

# 如果不寫參數,程序默認會0.5s 調用一次來查看元素是否已經生成,如果本來元素就是存在的,那麼會立即返回。下面是一些內置的等待條件,你可以直接調用這些條件,而不用自己寫某些等待條件了。

presence_of_element_located元素加載出,傳入定位元組,如(By.ID,'p')
element_to_be_clickable元素可點擊

visibility_of_element_located元素可見,傳入定位元組visibility_of可見,傳入元素對象
text_to_be_present_in_element某個元素文本包含某文字
text_to_be_present_in_element_value某個元素值包含某文字
frame_to_be_available_and_switch_to_itframe加載並切換
invisibility_of_element_located元素不可見
staleness_of判斷一個元素是否仍在DOM,可判斷頁面是否已經刷新
element_to_be_selected元素可選擇,傳元素對象
element_located_to_be_selected元素可選擇,傳入定位元組
element_selection_state_to_be傳入元素對象以及狀態,相等返回True,否則返回False
element_located_selection_state_to_be傳入定位元組以及狀態,相等返回True,否則返回False
alert_is_present是否出現Alert

selenium配置

提高效率

無界面瀏覽器

  • 火狐
# 創建火狐參數對象
opt = webdriver.FirefoxOptions()    

# 把火狐設置成無頭模式,不論windows還是linux都可以,自動適配對應參數
opt.set_headless()   

# 不制定options選項則是普通有頭瀏覽器
driver = webdriver.Firefox(firefox_options=opt)   


from selenium import webdriver
from time import sleep

opt = webdriver.FirefoxOptions()
opt.set_headless()
driver = webdriver.Firefox(firefox_options=opt)


driver.get("http://www.baidu.com")
print(driver.page_source)
sleep(2)
driver.quit()
  • 谷歌
# 創建chrome參數對象
opt = webdriver.ChromeOptions()    

# 把chrome設置成無頭模式,不論windows還是linux都可以,自動適配對應參數
opt.set_headless()   

# 不制定options選項則是普通有頭瀏覽器
driver = webdriver.Chrome(options=opt)    


from selenium import webdriver
from time import sleep

opt = webdriver.ChromeOptions()
opt.set_headless()
driver = webdriver.Chrome(options=opt)
driver.get("http://www.baidu.com")
print(driver.page_source)
sleep(2)
driver.quit()

禁止加載圖片

  • 火狐
    opt = webdriver.FirefoxOptions()
    opt.set_headless()
    f = webdriver.FirefoxProfile()
    f.set_preference("permissions.default.stylesheet", 2)
    f.set_preference('permissions.default.image', 2)
    driver = webdriver.Firefox(firefox_options=opt,firefox_profile=f)
  • 谷歌
    chrome_options = webdriver.ChromeOptions()
    prefs = {"profile.managed_default_content_settings.images": 2}
    chrome_options.add_experimental_option("prefs", prefs)
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    driver = webdriver.Chrome(chrome_options=chrome_options)

中斷網頁加載

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.set_page_load_timeout(5)
startTime = time.time()
print(time.time())
try:
    driver.get("http://www.yuduxx.com/")
except:
    driver.execute_script('window.stop ? window.stop() : document.execCommand("Stop");')
    print("-----------------")
print(driver.page_source)
print(time.time() - startTime)

設置UA

  • 火狐
from selenium import webdriver


profile = webdriver.FirefoxProfile()

user_agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36 OPR/37.0.2178.32"

profile.set_preference("general.useragent.override", user_agent)
profile.update_preferences()

driver = webdriver.Firefox(firefox_profile=profile)
driver.get('http://service.spiritsoft.cn/ua.html')
print(driver.page_source)
  • 谷歌
from selenium import webdriver

chromeOptions = webdriver.ChromeOptions()


# 一定要注意,=兩邊不能有空格
chromeOptions.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"')


browser = webdriver.Chrome(chrome_options = chromeOptions)
# 查看本機UA
# http://www.useragentstring.com/
browser.get("http://service.spiritsoft.cn/ua.html")
print(browser.page_source)

設置代理

  • 火狐
from selenium import webdriver

profile = webdriver.FirefoxProfile()

profile.set_preference('network.proxy.type', 1)
profile.set_preference('network.proxy.http', '115.239.240.230')
profile.set_preference('network.proxy.http_port', 808)  # int

profile.update_preferences()

#"123.160.224.146, 123.160.224.146"

driver = webdriver.Firefox(firefox_profile=profile)
driver.get('http://httpbin.org/ip')
print(driver.page_source)
  • 谷歌
from selenium import webdriver
chromeOptions = webdriver.ChromeOptions()

# 設置代理
chromeOptions.add_argument("--proxy-server=http://115.239.240.230:808")
# 一定要注意,=兩邊不能有空格,不能是這樣--proxy-server = http://115.239.240.230:808
browser = webdriver.Chrome(chrome_options = chromeOptions)

# 查看本機ip,查看代理是否起作用
browser.get("http://httpbin.org/ip")
print(browser.page_source)

# 退出,清除瀏覽器緩存
browser.quit()

任務

1.案例:網易科技新聞
http://tech.163.com/
在這裏插入圖片描述

2.案例:京東商品檢索信息爬蟲
https://search.jd.com/Search?keyword=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&enc=utf-8&wq=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&pvid=5ee52edd0bb54a0097f4a72b67d86468
在這裏插入圖片描述

3.案例:瓜子二手車
https://www.guazi.com/zz/buy/
在這裏插入圖片描述

4.案例:微博模擬登陸
https://weibo.com/
在這裏插入圖片描述

5.案例:微博信息爬蟲
https://weibo.com/p/1003061826792401?is_hot=1
在這裏插入圖片描述

6.案例:亞馬遜中國
https://amazon.cn/s?k=筆記本電腦&lo=grid&__mk_zh_CN=亞馬遜網站&qid=1567598049&ref=sr_pg_1
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章