selenium 和 IP代理池
3.1 selenium
selenium:
Selenium 是一個自動化測試工具,利用它可以 驅動瀏覽器 執行特定的動作,如點擊、下拉等操作(模擬瀏覽器操作)
同時還可以獲取瀏覽器當前呈現的頁面的源代碼,做到可見即可爬
Selenium支持非常多的瀏覽器,如 Chrome、Firefox、PhantomJS等
瀏覽器對象的初始化 并將其賦值為 browser 對象。接下來,我們要做的就是調用 browser 對象,讓其執行各個動作以模擬瀏覽器操作
eg:要使用google瀏覽器
訪問頁面:get方法
eg:
查找節點(比如 找到賬號輸入框):
1:單個節點
返回:WebElement 類型
find_element_by_id
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
變式:
find_element(By.a,b)——參數a輸入屬性,參數b輸入值
2:多個節點(淘寶左邊所有的導航欄條目):
如果我們用 find_element()方法,只能獲取匹配的第一個節點
如果用 find_elements()方法,返回:列表類型,包含所有符合要求的節點,列表中的每個節點是 WebElement 類型
find_elements_by_id
find_elements_by_name
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
節點交互(模擬人的操作—有特定對象):
輸入文字—— send_keys()方法
清空文字—— clear()方法
點擊按鈕—— click()方法
動作鏈(模擬人的操作—無特定對象):
沒有特定的執行對象,比如鼠標拖曳、鍵盤按鍵等
用另一種方式來執行——動作鏈
http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains
獲取節點信息:
Selenium 提供了選擇節點的方法,返回的是 WebElement 類型
它也有相關的方法和屬性來直接提取節點信息,如屬性、文本等。
這樣的話,我們就可以不用通過解析源代碼來提取信息了,方便
屬性值:
get_attribute() 方法來獲取節點的屬性,但是其前提是先選中這個節點
通過get_attribute()方法,然后傳入想要獲取的屬性名,就可以得到它的值
文本:
每個 WebElement 節點都有 text 屬性,直接調用這個屬性就可以得到節點內部的文本信息
——相當于 Beautiful Soup 的 get_text()方法
WebElement 節點還有一些其他屬性
比如
id 屬性可以獲取節點 id
location 屬性可以獲取該節點在頁面中的相對位置
tag_ name 屬性可以獲取標簽名稱
size 屬性可以獲取節點的大小,也就是寬高
繁瑣一點的話,就用page_source 屬性獲取網頁的源代碼,接著使用解析庫
切換Frame(子頁面):
switch_to.frame()方法
Selenium在一個 頁面中,完成 對這個頁面 的操作。在父頁面無法對子Frame操作
延時等待:
確保節點已經加載出來——在 Selenium 中,get()方法會在網頁框架加載結束后
結束執行,此時可能并不是瀏覽器完全加載完成的頁面
1:隱式
換句話說,當查找節點 而節點并沒有立即出現的時候,隱式等待 將等待一段時間再查找DOM,默認的時間是0
implicitly_ wait()
2:顯式
隱式等待的效果并沒有那么好,因為我們只規定了一個 固定時間,而頁面的加載時間會受到網絡條件的影響
顯式——它指定一個等待條件(要查找的節點),然后指定一個最長等待時間。
如果在規定時間內滿足 等待條件(加載出來了這個節點),就返回要查找的節點;
如果到了規定時間還沒有 等待條件(沒有加載出該節點),則拋出超時異常
eg:
更多等待條件的參數及用法,參考官方文檔:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions
前進后退:
back()方法后退,
forward()方法前進
eg:
Cookies:
對 Cookies 進行操作
例如獲取、添加、刪除 Cookies 等
get_cookies() ——獲取
add_cookie()——添加
delete_all_cookies() ——刪除所有的 Cookies
選項卡:
execute_ script()方法
switch_ to_ window()——切換選項卡
異常處理:
try except 語句——捕獲異常,放置程序遇到異常而中斷
實戰:selenium模擬登陸163(126)郵箱
# 登陸,打開網頁頁面,加載成功后,找到賬號密碼框,輸入賬號密碼,點擊登陸 # 對應 #訪問頁面。查找輸入框等節點。輸入cookes等信息,模擬點擊(交互)from selenium import webdriver import timeurl = 'https://www.126.com/' def open_page(url):browser = webdriver.Chrome()browser.get('https://www.126.com/') #打開網頁time.sleep(2)#以上代碼OKbrowser.switch_to.frame(0)#關鍵#找到賬號框,密碼框,登陸按鈕。然后輸入信息card = browser.find_element_by_name('email')#賬號框card.send_keys('dengzhanh')password = browser.find_element_by_name('password') #密碼框password.send_keys('*******')login = browser.find_element_by_id('dologin')#登陸按鈕login.click()def main():open_page(url)if __name__=='__main__':main()問題:
1—browser.switch_to.frame(0) 是在同一界面選擇一個子界面么?()內的參數怎么填?
2—賬號密碼框 在源碼中,如何快捷地找到其 屬性?
3.2 IP ——參考:網絡爬蟲開發實戰
IP(代理):
網站為了防止被爬取,會有反爬機制
服務器會檢測某個IP在單位時間內的請求次數,如果超過了這個閾值,就會直接拒絕服務,返回一些錯誤信息——可以稱為封IP
應對IP被封的問題:
修改請求頭,模擬瀏覽器(把你當做是個人)訪問
采用代理IP 并輪換
設置訪問時間間隔(同樣是模擬人,因為人需要暫停一會)
代理:在本機 和 服務器 之間搭橋
本機不直接發送請求,通過橋(代理服務器)發送請求
web代理 通過橋 返回 響應
請求庫的代理設置方法
1:requests 的代理設置:只需要構造代理字典,然后通過 proxies
數即可,而不需要重新構建 pener
如果需要 驗證,下面的代碼輸入兩個部分即可
proxy= 'username:password@代理 ’
使用 SOCKS5 代理(需要安裝SOCKS庫)
1:
2:全局設置
import requests import socks import socket socks.set_default_proxy(socks . 50CKS5,’127.0 .0.1 ’, 9742) socket.socket = socks.socksocket2:Selenium代理設置:
以Chrome為例
若是 認證代理:
需要在本地創建一個 manifest.json 配置文件 和 background.js 腳本來設置認證代理
運行代碼之后本地會生成一個 proxy auth __plugin.zip 文件來保存當前配置
代理池:
不是所有的代理都能用,所以要進行 篩選,提出不可用代理,保留可用代理
∴ 建立代理池
設計代理的基本思路:(代理池的目標)
1:存儲模塊(存代理)——負責存儲抓取下來的代理。首先要保證代理不重復,要標識代理的可用情況,還要動態實時處理每個代理。
所以一種比較高效方便的存儲方式就是使用 Redis的Sorted Set,即有序集合
2:獲取模塊(抓代理)——需要定時在各大代理網站抓取代理。代理可以是免費公開代理也可以是付費代理,代理的形式都是 IP 加端口,此模塊盡量從不同來源獲取,盡量抓取高匿代理,抓取成功之后將 可用代理 保存到數據庫中
3:檢測模塊(能用否)——需要定時檢測數據庫中的代理。這里需要設置一個檢測鏈接,最好是爬取哪個網站就檢測哪個網站,這樣更加有針對性,如果要做一個通用型的代理,那可以設置百度等鏈
接來檢測。
另外,我們需要標識每一個代理的狀態,如設置分數標識,100分代表可用,分數越少代表越不可用。——檢測一次,如果代理可用,我們可以將分數標識立即設置為100分,也可以在原基礎上加1分;如果代理不可用,可以將分數標識減1分,當分數減到一定閾值后,代理就直接從數據庫移除。通過這樣的標識分數,我們就可以辨別代理的可用情況,選用的時候會更有針對性
4:接口模塊(拿出來)——需要用 API 來提供對外服務的接口。其實我們可以直接連接數據庫采取對應的數據,但是這樣就需要知道數據庫的連接信息,并且要配置連接。
而比較安全和方便的方式就是提供一個 Web API 接口,我們通過訪問接口即可拿到可用代理。另外,由于可用代理可能有多個,那么我們可以 設置一個 隨機返回 某個可用代理 的接口,這樣就能保證 每個可用代理都可以取到,實現 負載均衡。
根據以上,設計代理池架構
注:
存儲模塊——使用 Redis 有序集合,用來做代理的 去重 和 狀態標識,同時它也是中心模塊和基
礎模塊,將其他模塊串聯起來
獲取模塊——定時從代理網站獲取代理,將獲取的代理傳遞給存儲模塊,并保存到數據庫
檢測模塊——定時通過存儲模塊獲取所有代理,并對代理進行檢測,根據不同的檢測結果對代理
設置不同的標識
接口模塊——通過 WebAPI 提供服務接口,接口通過連接數據庫并通過Web 形式返回可用的代理
4個模塊的實現
1:存儲模塊
這里我們使用 Redis 的有序集合,集合的每一個元素都是不重復的
對于代理池來說,集合的元素就變成了 個個代理,也就是 IP 加端口的形式,
eg:60.207.237.111 :8888 ,這樣的一個代理就是集合的一個元素。
另外,有序集合的每一個元素都有一個分數字段,分數是可以重復的,可以是浮點數類,也可以是整數類型。
該集合會根據每一個元素的分數對集合進行排序,數值小的排在前面,數值大的排在后面,這樣就可以實現集合元素的排序了。
對于代理池來說,這個分數可以作為判斷一個代理是否可用的標志, 100 為最高分,代表最可用,0為最低分,代表最不可用。
如果要獲取可用代理,可以從代理池中隨機獲取分數最高的代理,注意是隨機,這樣可以保證每個可用代理都會被調用到
引入分數機制
定義常量,比如:分數(最大最小初始)、Redis的連接信息(地址、端口、密碼)、有序集合的鍵名(獲取)
定義類,用于操作Redis的有序集合,其中定義一些方法,用于處理集合中的元素。
獲取模塊:
定義一個 Crawler 來從各大網站抓取代理
將獲取代理的每個方法統一定義為以Crawl 開頭,這樣擴展的時候只需要添加Crawl 開頭的方法即可。
這些方法都定義成了生成器,通過 yield返回代理。程序首先獲取網頁,然后用解析,解析出 IP加端口的形式的代理 然后返回
然后定義了一個 get_proxies ()方法,將所有以 crawl 開頭的方法調用一遍,獲取每個方法返回的代理 并 組合成列表形式返回
依次通過 get_proxies方法調用,得到各個方法抓取到的代理,然后再利用 Redi sClien的add方法加入數據庫,這樣獲取模塊的工作就完成了
檢測模決:
使用異步請求庫aiohttp
接口模塊:
代理池可以作為一個獨立服務運行,我們最好增加一個接口模塊,并以 WebAPI的形式暴露可用代理——獲取代理只需要請求接口即可
調度模塊:
調度模塊就是調用以上所定義的 3個模塊,將這 個模塊通過多進程的形式運行起來
實戰:
總結
以上是生活随笔為你收集整理的selenium 和 IP代理池的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 伺服系统选型方案
- 下一篇: 搭建dns服务器添加 txt记录