簡介
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