文章目錄
Selenium 簡介
Selenium 不同於requests這種模擬瀏覽器進行數據爬取的庫,而是直接運行在瀏覽器中,就如同真正的用戶進行操作selenium中文文檔selenium暫未發現官方文檔,上述文檔爲愛好者自制
Selenium 部署
selenium庫並非內置,所以需要導入pip install selenium
selenium是一個自動化程序,自動操控瀏覽器,所以需要一個插件可以對瀏覽器進行操作
- Chrome(外網,需要魔法)國內用戶可以去淘寶鏡像下載 淘寶鏡像Chrome
- Firefox
- edge
將下載的驅動放入環境變量中(如果不知道什麼是環境變量就放在Python安裝文件夾中即可)
Selenium使用方法
Selenium是一個很龐大的庫,這裏不建議直接使用import直接導入全庫,而是用到什麼導入什麼。
啓動Selenium
啓動selenium的話我們只需導入from selenium import webdriver
即可
顧名思義,這個是用於啓動瀏覽器的方法webdriver
後面可以跟着需要啓動的瀏覽器名稱
比如.Firefox()
(火狐瀏覽器).Edge()
windows10系統默認瀏覽器.Chrome()
谷歌瀏覽器.Opera()
歐朋瀏覽器.Safari()
Mac等蘋果設備自帶瀏覽器,啓用這些瀏覽器的前提是你已經下載好驅動並放入環境變量中(這些瀏覽器方法首字母需要大寫!!!)
driver = webdriver.Firefox()
啓動火狐瀏覽器並將此對象賦值給driver
driver方法 | 作用 |
---|---|
.name |
檢查驅動是基於什麼瀏覽器(假設爲.Firefox(),返回值則爲firefox) |
.get(網址) |
已get方法打開指定網址 |
.title |
返回當前頁面標題 |
.current_url |
當前url |
.page_source |
獲取當前頁面的源(重要方法) |
.back() |
在瀏覽器的歷史記錄中後腿一步。 |
.forward() |
在瀏覽器歷史記錄中向前邁進了一步。 |
.refresh() |
刷新頁面 |
.implicitly_wait(時間) |
隱式等待(下方有此方法詳細使用說明) |
.set_script_timeout(時間) |
異步加載頁面時等待的時間 |
.set_page_load_timeout(時間) |
設置等待頁面加載的時間,超出後報錯(在get前使用) |
.desired_capabilities |
返回當前驅動的信息 |
對瀏覽器的操作
使用方法 | 作用 |
---|---|
.current_window_handle |
返回當前窗口的句柄(系統會給每個窗口分配一個句柄,可以根據句柄移動窗口、改變窗口大小、把窗口最小化等等。) |
.window_handles |
返回所以窗口的句柄 |
.maximize_window() |
最大化窗口 |
.minimize_window() |
最小化窗口 |
.fullscreen_window() |
將窗口全屏 |
.set_window_size(寬,高) |
指定窗口的大小 |
.get_window_size() |
獲取窗口的大小 |
,set_window_position(x,y) |
設置窗口的位置 |
.get_window_position() |
獲取窗口的位置 |
.set_window_rect(x,y,寬,高) |
設置狀況的位置以及大小 |
.get_window_rect() |
獲取當前窗口的位置以及大小 |
.close() |
關閉窗口 |
.quit() |
退出驅動程序並關閉窗口 |
.switch_to |
用於切換焦點(多窗口切換與切換到頁面中內置頁面frame元素中使用) |
查找元素
常用查找方法 | 作用 |
---|---|
.find_element_by_id(id名) |
按id查找元素。(找到第一個符號要求的元素後立即返回) |
.find_elements_by_id(id名) |
按id查找多個元素。(找到多個符合要求的元素後合併成列表返回) |
.find_element_by_class_name(class名) |
按class名查找元素。(同樣擁有查找多個元素的elements方法) |
.find_element_by_xpath(xpath規則) |
按xpath規則查找元素。(同樣擁有查找多個元素的elements方法) |
.find_element_by_link_text(文本) |
根據標籤中的文本查找元素,必須要全文匹配,比如<p>全文匹配</p>時文本必須爲’全文匹配’(同樣擁有查找多個元素的elements方法) |
.find_element_by_partial_link_text(文本) |
根據標籤中的文本查找元素,部分匹配即可,比如<p>全文匹配</p>時文本可以爲’匹配’(同樣擁有查找多個元素的elements方法) |
.find_element_by_name(name名) |
按名稱查找元素。(同樣擁有查找多個元素的elements方法) |
.find_element_by_tag_name(HTML標籤) |
按HTML標籤查找元素。(同樣擁有查找多個元素的elements方法) |
.find_element_by_css_selector(css選擇器) |
根據css選擇器查找元素。(同樣擁有查找多個元素的elements方法) |
.find_element(策略器 ,'元素') |
策略器包含By.ID ,By.TAG_NAME ,By.CLASS_NAME ,By.NAME (同樣擁有查找多個元素的elements方法) 策略器需要導入from selenium.webdriver.common.by import By |
行爲鏈(模擬鼠標與鍵盤)
模擬鼠標的單擊,雙擊,右擊,懸浮等操作。需要引入from selenium.webdriver.common.action_chains import ActionChains
。創建行爲鏈需要先實例化一個鼠標ActionChains(WebDriver實例)
比如mouse = ActionChains(self.driver)
行爲鏈模擬鼠標方法 | 作用 |
---|---|
.perform() |
執行操作(行爲鏈是一系列操作,最後需要使用此方法讓其他方法開始執行,類似數據庫事務的提交操作) |
.reset_actions() |
清除操作(相當於數據庫中事務的回滾) |
.click(點擊對象) |
點擊左鍵 |
.click_and_hold(點擊對象) |
按住左鍵(與點擊不同,這是按住不松) |
.context_click(點擊對象) |
點擊右鍵 |
.double_click(點擊對象) |
雙擊鼠標左鍵 |
.drag_and_drop(下移對象, 上移對象) |
將指定元素上下移動 |
.drag_and_drop_by_offset(點擊對象, x, y) |
點擊指定對象後拖動至指定xy區域 |
.move_by_offset(x, y) |
移動鼠標到座標xy |
.move_to_element(指定對象) |
將鼠標移動到指定對象上並開始懸停 |
.move_to_element_with_offset(指定對象, x, y) |
將鼠標移動到指定對象後並偏移xy。 |
.release(指定對象) |
在指定對象上放開鼠標,不指定對象則爲當前位置放開鼠標 |
行爲鏈模擬鍵盤方法 | 作用 |
---|---|
.key_down(按鍵, 發送對象) |
按下鍵盤按鍵,但不釋放鍵盤(需要同時按住多鍵時使用),每次只能傳入一個按鍵,如果沒有發送對象,則想當前焦點發送 |
.send_keys(按鍵) |
選擇按鍵 |
.key_up(按鍵, 發送對象) |
放開按鍵,如果沒有發送對象,則想當前焦點發送 |
send_keys_to_element(發送對象, 按鍵) |
點擊鍵盤 |
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
# 假設需要按ctrl+c
driver = webdriver.Firefox()
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
保存網頁快照
使用方法 | 作用 |
---|---|
.get_screenshot_as_file(文件路徑.png) |
要將屏幕快照保存到指定路徑.save_screenshot(文件路徑.png) 方法作用相同 |
.get_screenshot_as_png() |
獲取屏幕快照的二進制並作爲返回值返回 |
.get_screenshot_as_base64() |
獲取屏幕快照的base64編碼字符串並作爲返回值返回,在HTML中的嵌入圖像中非常有用。 |
對cookie的操作
使用方法 | 作用 |
---|---|
.get_cookies() |
用字典的方式返回獲取的cookies |
.get_cookie(cookie名) |
按cookie尋找cookie |
.delete_cookie(名稱) |
刪除指定名稱的cookie |
.delete_all_cookies() |
刪除全部cookie |
.add_cookie(cookie) |
將cookie添加到當前網頁 |
頁面等待
隱式等待
隱式等待只需要使用driver.implicitly_wait(等待時間)
方法即可。隱式等待一旦設置後,整個程序的生命週期中都將會啓動,下列代碼會讓瀏覽器等待網頁加載,但如果超過等待時間,則會出現異常(隱式等待一旦設定,整個程序中使用webdriver尋找元素都會進行等待,所以不太推薦使用隱式等待,大多數情況下可以使用顯式等待)
下面有個網站,因爲圖片應該使用了懶加載(校點在哪,加載哪裏,我們直接獲取網頁源碼會無法得到想要的結果,所以我們就可以使用等待,等我們需要的元素出現後在保存頁面)
from selenium import webdriver
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打開瀏覽器"""
driver = webdriver.Firefox()
# 最小化瀏覽器
driver.minimize_window()
return driver
def get_url(self):
"""訪問url"""
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 隱式等待
driver.implicitly_wait(1)
driver.find_element_by_css_selector('img[class="xxqg-image"]')
return driver.page_source
def run(self):
"""啓動"""
# 保存網頁源碼
html = self.get_url()
print(html)
if __name__ == '__main__':
Study().run()
顯式等待
顯式等待需要使用到WebDriverWait
與expected_conditions
顯式等待要用到的方法我們需要先導入一下
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
顯式等待相較於隱式等待有着更強的針對性,可以只針對一個地方進行等待,而不是直接使全局都進行等待,作用幾乎一致
# 隱式等待
driver.implicitly_wait(3)
driver.find_element_by_css_selector('img[class="xxqg-image"]')
# 顯示等待(內都)
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
WebDriverWait會對until中的期望條件不斷進行測試,如果在指定時間無法通過測試,那麼就會返回異常(默認0.5秒一次,可以在WebDriverWait()
方法第三個參數處更改默認時間,如WebDriverWait(driver, 3, 0.1)
)WebDriverWait()
除了.until()
還有.until_not()
方法
相對於隱式等待,顯示等待提供了很多方法可以作爲等待條件expected_conditions(EC)
常用期望條件
常用期望(expected_conditions )方法 | 作用 |
---|---|
.title_is(標題) |
檢查標題是否達到預期(匹配則返回True,否則返回false。) |
.title_contains(標題) |
檢查標題是否包含大小寫 |
.presence_of_element_located((By類,'期望條件')) |
檢查期望條件是否在頁面源碼中出現,不可以見元素也算(這裏傳入的必須是一個元組) |
.presence_of_all_elements_located((By類,'期望條件')) |
檢查是否滿足一直一個期望條件 |
.visibility_of_element_located((By類,'期望條件')) |
檢查期望條件是否在可見頁面中出現,必須爲可見元素,在頁面中寬高大於0的爲可見元素(這裏傳入的必須是一個元組) |
.visibility_of(期望元素) |
頁面中是否出現期望元素 |
presence_of_all_emement_located() |
檢查頁面是否所以元素都已經加裝完畢 |
.url_contains(期望元素) |
檢查url是否和期望元素完全符合 |
.url_to_be(期望元素) |
與.url_contains(元素) 方法作用類型,區別是url_to_be使用雙等==判斷是否一致url_contains使用is判斷是否一致 |
.url_matches(期望元素) |
檢查url中是否包含期望元素 |
.url_changes(期望元素) |
是否與期望元素不同 |
.element_to_be_cliable() |
檢查期望調試是否已經可用並且可以點擊 |
期望條件有很多我並沒有列舉出全部,有需要的可以去selenium庫中的expected_conditions.py文件中查看
打開多窗口與切換窗口
如果使用多個get,則會打開多個瀏覽器,如果我們想在同一個瀏覽器中啓動做個窗口需要用到.execute_script()
方法執行js命令,打開一個新窗口的js命令爲window.open('網址')
打開窗口需要用到
driver.get('https://www.baidu.com')
driver.execute_script('window.open("https://www.baidu.com/baidu?wd=python")')
切換窗口我們需要用到.switch_to
方法切換窗口與.window_handles
方法來獲取窗口的句柄
.switch_to常用方法 | 用法 |
---|---|
.switch_to.window(窗口句柄) | 切換窗口焦點(必須拿到窗口句柄,可以通過.window_handles 方法獲得當前瀏覽器中全部窗口的句柄),如driver.switch_to.window(driver.window_handles[0]) |
.switch_to.frame() | 切換到嵌套頁面中(HTML中<iframe></iframe> 標籤中的內容即爲嵌套頁面),可以使用多種方法找到嵌套頁面,如driver.switch_to.frame('frame_name') driver.switch_to.frame(1) driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) |
.switch_to.parent_frame() | 切換到父頁面中 |
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打開瀏覽器"""
driver = webdriver.Firefox()
# 最小化瀏覽器
driver.minimize_window()
return driver
def get_url(self):
"""訪問url"""
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 網頁邏輯太差,且圖片應該爲懶加載,所以需要使用此條件來判斷是否加載完成,註釋下方兩行獲取的網頁將不完整
# 顯式等待
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
return driver.page_source
def run(self):
"""啓動"""
# 保存網頁源碼
html = self.get_url()
print(html)
if __name__ == '__main__':
Study().run()
智慧樹登陸測試
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
"""
測試目標(此模塊只是單純的用於selenium模塊的學習使用)
自動登錄智慧樹(https://passport.zhihuishu.com/login)
"""
# Wisdom(智慧)
class WisdomTree:
def __init__(self, uid, password, school='在這裏寫上一個學校'):
# 手機號登陸(參數讓登陸後直接跳轉到個人頁面)
self.login_url = 'https://passport.zhihuishu.com/login?service=https://onlineservice.zhihuishu.com/login/gologin'
# 學號登陸
self.login_id_url = 'https://passport.zhihuishu.com/login?service=https://onlineservice.zhihuishu.com/login/gologin#studentID'
self.id_name = uid
self.password = password
self.school_name = school
self.driver = None
def open_web(self):
"""打開瀏覽器"""
self.driver = webdriver.Firefox()
# 最小化瀏覽器
self.driver.minimize_window()
def login_web(self):
"""登陸網站"""
while True:
# 判斷輸入的爲手機號還是學號(1開頭爲手機號2開頭爲學號,其餘開頭爲輸入錯誤)
if self.id_name[0] == '1' and len(self.id_name) == 11:
# 打開手機賬號的登陸網址
self.driver.get(self.login_url)
# 尋找登陸名輸入框並輸入用戶名
login_name = self.driver.find_element_by_id('lUsername')
login_name.send_keys(self.id_name)
# 尋找密碼欄輸入框並輸入密碼
login_password = self.driver.find_element_by_id('lPassword')
login_password.send_keys(self.password)
# 執行點擊(click)事件
login_click = self.driver.find_element_by_class_name('wall-sub-btn')
login_click.click()
return '正在通過電話號登錄'
elif self.id_name[0] == '2' and len(self.id_name) == 11:
# 打開學號賬號的登陸網址
self.driver.get(self.login_id_url)
# 尋找學校輸入框後輸入學校
school = self.driver.find_element_by_class_name('school-search-ipt')
school.send_keys(self.school_name)
# 選擇學校(填寫學校後需要鼠標出發點擊事件確定學校,否則無法登錄)
school_click = self.driver.find_element_by_xpath('//*[@id="schoolListCode"]/li')
# 實例化鼠標
mouse = ActionChains(self.driver)
# 點擊學校
mouse.click(school_click)
mouse.perform()
# 尋找學號欄並輸入學號
uid = self.driver.find_element_by_id('clCode')
uid.send_keys(self.id_name)
# 尋找密碼欄輸入框並輸入密碼
password = self.driver.find_element_by_id('clPassword')
password.send_keys(self.password)
# 執行點擊(click)事件
login_click = self.driver.find_element_by_class_name('wall-sub-btn')
login_click.click()
return '正在通過學號登錄'
else:
self.id_name = input('輸入有誤,請重新輸入學號或手機號:')
def run(self):
"""啓動代碼"""
# 打開瀏覽器
self.open_web()
# 登陸網站
self.login_web()
if __name__ == '__main__':
user = input('請輸入學號或手機號:')
pd = input('請輸入密碼:')
WisdomTree(user, pd).run()
圖片爬取測試(selenium+requests配合使用)
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Author : 尋覓
# @File : 圖片爬取.py
# @Time : 2020/2/12 13:24
# @Software: PyCharm
import requests
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
from bs4 import BeautifulSoup
class Study:
def __init__(self):
self.url = 'https://article.xuexi.cn/articles/index.html?art_id=15308933272663801705&item_id=15308933272663801705&study_style_id=feeds_default&showmenu=true&aid=15308933272663801705&item_type=1&recoid=12578234090040657023_1581240011&cid=&study_comment_disable=1&pid=34682268069627302&ref_read_id=8c1f7cad-22cf-473b-be16-3bf204f50468&ptype=100&source=share&share_to=wx_single&from=singlemessage'
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
self.driver = None
def open_web(self):
"""打開瀏覽器"""
driver = webdriver.Firefox()
# 最小化瀏覽器
driver.minimize_window()
return driver
def get_url(self):
"""訪問url"""
# 使用requests無法取得完整的頁面源碼,如下
# html = requests.get(self.url, headers=self.header)
# html.encoding = 'utf-8'
# return html.content
# 使用selenium
driver = self.open_web()
driver.get(self.url)
# 網頁邏輯太差,且圖片應該爲懶加載,所以需要使用此條件來判斷是否加載完成,註釋下方兩行獲取的網頁將不完整
# 隱式等待
# driver.implicitly_wait(1)
# driver.find_element_by_css_selector('img[class="xxqg-image"]')
# 顯式等待
WebDriverWait(driver, 3).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[class="xxqg-image"]'))
)
return driver.page_source
def write_html(self, html):
"""寫入到本地"""
with open('河南學習強國.html', 'w') as w:
w.write(html)
# extract(提取)
def data_extract(self, data):
"""數據提取"""
bs_data = BeautifulSoup(data, 'lxml')
data = bs_data.select('img[class="xxqg-image"]')
img_url = []
for i in data:
img_url.append(i['data-src'])
return img_url
def get_img(self, img_url):
"""將圖片鏈接轉爲二進制格式的圖片"""
img_data = []
i = 1
print('獲取的網頁中首個圖片爲:', img_url[0])
for url in img_url:
print('\r共有%d張圖片。正在下載第%d張圖片' % (len(img_url), i), end=" ")
img = requests.get(url, headers=self.header)
img_data.append(img)
i += 1
return img_data
def write_img(self, img_data):
"""保存圖片"""
i = 1
for img in img_data:
with open(f'圖片/第{i}張圖片.jpg', 'wb') as w:
print('\r共有%d張圖片。正在保存第%d張圖片' % (len(img_data), i), end=" ")
w.write(img.content)
i += 1
def run(self):
"""啓動"""
# 保存網頁源碼
html = self.get_url()
# 保存網頁源碼
self.write_html(html)
# 獲取網頁源碼
# html = open('河南學習強國.html').read()
# 提取圖片鏈接
# print('正在獲取圖片鏈接')
# img_url = self.data_extract(html)
# 將鏈接轉換爲圖片
# print('正在將鏈接轉換爲圖片')
# img_data = self.get_img(img_url)
# 保存圖片
# print('\n正在保存')
# self.write_img(img_data)
# print('\n程序完成')
if __name__ == '__main__':
Study().run()