滑動驗證碼介紹
本篇部落格涉及到的驗證碼為滑動驗證碼,不同於極驗證,本驗證碼難度略低,需要的將滑塊拖動到矩形區域右側即可完成。
這類驗證碼不常見了,官方介紹地址為:promotion.aliyun.com/ntms/act/ca…
使用起來肯定是非常安全的了,不是很好通過機器檢測
如何判斷驗證碼型別
這個驗證碼的標識一般比較明顯,在頁面原始碼中一般存在一個 nc.js 基本可以判定是阿里雲的驗證碼了
<script type="text/javascript" src="//g.alicdn.com/sd/ncpc/nc.js?t=1552906749855"></script>
複製程式碼
識別套路
截止到2019年3月18日,本驗證碼加入了大量的selenium關鍵字驗證,所以單純的模擬拖拽被反爬的概率滿高的,你也知道一般情況爬蟲具備時效性
不確保這種手段過一段時間還可以使用!
匯入selenium必備的一些模組與方法
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ActionChains
import time
import random
複製程式碼
在啟動selenium之前必須要設定一個本機的代理,進行基本的反[反爬] 處理,很多爬蟲在獲取使用者指紋的時候,都比較喜歡selenium,因為使用selenium模擬瀏覽器進行資料抓取,能夠繞過客戶JS加密,繞過爬蟲檢測,繞過簽名機制
但是selenium越來越多的被各種網站進行了相關遮蔽,因為selenium在執行的時候會暴露出一些預定義的Javascript變數(特徵字串),例如"window.navigator.webdriver",在非selenium環境下其值為undefined,而在selenium環境下,其值為true
下圖所示為selenium驅動下Chrome控制檯列印出的值 細緻的繞過去的方法,可能需要單獨的一篇部落格進行贅述了,這裡我只對上面的引數進行遮蔽,使用到的是之前部落格中涉及的mitmdump進行代理docs.mitmproxy.org/stable/conc…
mitmdump進行代理
技術參考來源:zhuanlan.zhihu.com/p/43581988
關於這個模組的基本使用,參考我前面的部落格即可,這裡核心使用瞭如下程式碼
indject_js_proxy.py
from mitmproxy import ctx
injected_javascript = '''
// overwrite the `languages` property to use a custom getter
Object.defineProperty(navigator, "languages", {
get: function() {
return ["zh-CN","zh","zh-TW","en-US","en"];
}
});
// Overwrite the `plugins` property to use a custom getter.
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
});
// Pass the Webdriver test
Object.defineProperty(navigator, 'webdriver', {
get: () => false,
});
// Pass the Chrome Test.
// We can mock this in as much depth as we need for the test.
window.navigator.chrome = {
runtime: {},
// etc.
};
// Pass the Permissions Test.
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
'''
def response(flow):
# Only process 200 responses of HTML content.
if not flow.response.status_code == 200:
return
# Inject a script tag containing the JavaScript.
html = flow.response.text
html = html.replace('<head>', '<head><script>%s</script>' % injected_javascript)
flow.response.text = str(html)
ctx.log.info('>>>> js程式碼插入成功 <<<<')
# 只要url連結以target開頭,則將網頁內容替換為目前網址
# target = 'https://target-url.com'
# if flow.url.startswith(target):
# flow.response.text = flow.url
複製程式碼
上述指令碼放置任意目錄,之後進行mitmdump的啟動即可
C:\user>mitmdump -s indject_js_proxy.py
Loading script indject_js_proxy.py
Proxy server listening at http://*:8080
複製程式碼
啟動之後,通過webdriver訪問
如果webDriver是綠色,也說明代理起作用了
selenium爬取
接下來就是通過selenium進行一些模擬行為的操作了,這部分程式碼比較簡單,編寫的時候參考一下注釋即可。
# 例項化一個啟動引數物件
chrome_options = Options()
# 新增啟動引數
chrome_options.add_argument('--proxy-server=127.0.0.1:8080')
# 將引數物件傳入Chrome,則啟動了一個設定了視窗大小的Chrome
driver = webdriver.Chrome(chrome_options=chrome_options)
複製程式碼
關鍵函式
def move_to_gap(tracks):
driver.get("https://passport.zcool.com.cn/regPhone.do?appId=1006&cback=https://my.zcool.com.cn/focus/activity")
# 找到滑塊span
need_move_span = driver.find_element_by_xpath('//*[@id="nc_1_n1t"]/span')
# 模擬按住滑鼠左鍵
ActionChains(driver).click_and_hold(need_move_span).perform()
for x in tracks: # 模擬人的拖動軌跡
print(x)
ActionChains(driver).move_by_offset(xoffset=x,yoffset=random.randint(1,3)).perform()
time.sleep(1)
ActionChains(driver).release().perform() # 釋放左鍵
複製程式碼
注意看到上述程式碼中有何核心的點 --- 拖拽距離的 列表tracks
if __name__ == '__main__':
move_to_gap(get_track(295))
複製程式碼
這個地方可以借鑑網上的方案即可
def get_track(distance):
'''
拿到移動軌跡,模仿人的滑動行為,先勻加速後勻減速
勻變速運動基本公式:
①v=v0+at
②s=v0t+(1/2)at²
③v²-v0²=2as
:param distance: 需要移動的距離
:return: 存放每0.2秒移動的距離
'''
# 初速度
v=0
# 單位時間為0.2s來統計軌跡,軌跡即0.2內的位移
t=0.1
# 位移/軌跡列表,列表內的一個元素代表0.2s的位移
tracks=[]
# 當前的位移
current=0
# 到達mid值開始減速
mid=distance * 4/5
distance += 10 # 先滑過一點,最後再反著滑動回來
while current < distance:
if current < mid:
# 加速度越小,單位時間的位移越小,模擬的軌跡就越多越詳細
a = 2 # 加速運動
else:
a = -3 # 減速運動
# 初速度
v0 = v
# 0.2秒時間內的位移
s = v0*t+0.5*a*(t**2)
# 當前的位置
current += s
# 新增到軌跡列表
tracks.append(round(s))
# 速度已經達到v,該速度作為下次的初速度
v= v0+a*t
# 反著滑動到大概準確位置
for i in range(3):
tracks.append(-2)
for i in range(4):
tracks.append(-1)
return tracks
複製程式碼
程式碼註釋已經新增好,可以自行查閱,臨摹一下即可明白
最後開始進行嘗試,實測中,發現可以自動拖動,但是,出現一個問題是最後被識別為機器,這個地方,我進行了多次的修改與調整,最終從程式碼層面發現實現確實有些複雜,所以改變策略,找一下chromedriver.exe是否有修改過的版本,中間去除了selenium的一些關鍵字,運氣不錯,被我找到了。
目前只有windows10版本和linux16.04版本 gitee地址:gitee.com/bobozhangyx…
下載之後,替換你的 chromedriver.exe
歡迎關注「非本科程式設計師」 回覆 【0411】獲取本篇部落格原始碼