騰訊DeepOcean原創文章:dopro.io/reptile.htm…
在“爬蟲的攻守之道(一)”中你可能已經瞭解到了無頭瀏覽器的作用以及使用的方法,那麼本篇文章就讓我們一起用無頭瀏覽器做點事情。是的你沒有看錯,我們要“搞”的物件就是百度指數這個網站,不知道你平時是否會應用到這裡面的資料呢?
今天的主要目標就是使用無頭瀏覽器登入百度指數網站,並且繞開它的人機驗證,不知道你發現沒有,當我們人為正常登入這個網站的時候就不會出現字母、數字或者漢字驗證碼,而使用無頭瀏覽器登入的時候就會出現這些驗證碼,閒言少敘我們直接開始正題。
一 正常人為登入為什麼不出現驗證碼?
我們在使用瀏覽器正常登入百度指數網站的時候發現一般不會彈出驗證碼的提示。但是如果你使用無頭瀏覽器去登入的時候就會出現驗證碼,那麼這兩者登入的區別在哪裡呢?
經過我不斷的驗證發現了兩個問題,當我們使用無頭瀏覽器登入的時候做一些類似於人類的操作,例如在視窗中滑動滑鼠,或者改變視窗的大小,這樣百度指數網站就會認為你是人為的在操作。
第二個問題就是在我們使用無頭瀏覽器輸入賬號和密碼的時候,我們在手動輸入密碼的時候或多或少的在輸入字元之間都會存在時間間隔,而使用無頭瀏覽器的時候程式會零間隔的輸入,這樣百度指數網站就會認為你是一個程式在輸入了。
二 python無頭瀏覽器準備
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
import sys
複製程式碼
word = sys.argv[1]
phone = '此處是你登入百度指數網站的使用者名稱'
password = '此處是你登入百度指數網站的密碼'
複製程式碼
在上面的程式碼中我們引入了一些python的庫,接下來就是使用無頭瀏覽器前的準備工作。
#開啟chrome無頭瀏覽器
opt = webdriver.ChromeOptions()
opt.set_headless()
driver = webdriver.Chrome(options=opt)
executor_url = driver.command_executor._url
session_id = driver.session_id
#將開啟的瀏覽區url和session_id儲存起來,提供給下一次應用
file = open('browserMsg.txt','w')
file.writelines([executor_url, 'n',session_id])
file.close()
複製程式碼
driver.implicitly_wait(20)
driver.set_window_size(1000, 800)
driver.get("index.baidu.com/v2/main/ind…"+ word +"?words="+ word)
複製程式碼
在上面的程式碼中我們使用webdriver的內建函式初始化了無頭瀏覽器,你可能發現我使用了executor_url和session_id變數儲存了點東西,沒錯,我將此次開啟的瀏覽器資訊(url和sessionId)儲存在了一個txt檔案中,這樣下次我再使用百度指數的時候只需要使用python連線上這個被儲存資訊的無頭瀏覽器程式,那麼就可以節省掉重複登入所帶來的風險了,並且還能節省程式數目(此處如果你不需要的話,無需關注)。
接下來我們隱式等待了20秒,並且將無頭瀏覽器的視窗設定為了寬1000高800(你可以改變數值),最後我們開啟了百度指數的網站,並且連結中帶有我們想要查詢的詞。
三 進軍
time.sleep(1)
driver.set_window_size(1200, 800)
time.sleep(1)
driver.set_window_size(1000, 800)
time.sleep(2)
複製程式碼
上面程式碼的作用是先將無頭瀏覽器視窗的寬變為1200,然後再變為1000,為了使得此處的操作更像人為操作,我加了一些延時效果,接下來就是輸入密碼的環節了。
getUserPhoneDom = driver.find_element_by_id('TANGRAM__PSP_4__userName')
getUserPassDom = driver.find_element_by_id('TANGRAM__PSP_4__password')
複製程式碼
for i in phone:
getUserPhoneDom.send_keys(i)
time.sleep(.4)
for j in password:
getUserPassDom.send_keys(j)
time.sleep(.4)
複製程式碼
在上面的程式碼中我先使用了getUserPhoneDom 變數儲存了需要輸入使用者名稱的輸入框資訊,使用getUserPassDom 變數儲存了需要輸入密碼的輸入框資訊,然後使用for迴圈讀取我們在上面定義的phone和password變數的字元資訊,並且每個字元輸入間隔了400毫秒,這樣做百度指數就認為你是人為的在輸入了。
time.sleep(1)
action=ActionChains(driver)
loginDom = driver.find_element_by_id('TANGRAM__PSP_4__submit')
action.move_to_element(loginDom).click().perform()
複製程式碼
當我們輸入完成使用者名稱和密碼以後我們只需要找到登入按鈕的DOM然後進行點選事件就OK了,到這裡你就可以成功的繞開百度指數的人機驗證了。
四 總結
繞開某一個網站的人機驗證,重點在於讓機器覺著你是人,而不是它的同類,但是機器覺著你是不是機器的重點在於設計這個機器的人所設定的一些檢驗手段。
對於百度指數來說它的主要檢驗手段在於你開啟瀏覽器時的操作,以及輸入使用者名稱和密碼時的操作,我寫這篇文章的時間是2018年11月18日,在這個節點之前呢,我使用上面的方式繞開百度指數的人機驗證沒有問題,以後有沒有問題,或者說有了問題如何解決還是要開發你的大腦了。
本文的最後我附上我全部的程式碼你可以複製下來,並且安裝好對應的python包,以及無頭瀏覽器的環境體驗一下。
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
import sys
word = sys.argv[1]
phone = '18846927659'
password = 'chitianshi...'
#登入百度指數網站
def login(word, phone, password):
#開啟chrome無頭瀏覽器
opt = webdriver.ChromeOptions()
opt.set_headless()
driver = webdriver.Chrome(options=opt)
executor_url = driver.command_executor._url
session_id = driver.session_id
#將開啟的瀏覽區url和session_id儲存起來,提供給下一次應用
file = open('browserMsg.txt','w')
file.writelines([executor_url, 'n',session_id])
file.close()
driver.implicitly_wait(20)
driver.set_window_size(1000, 800)
driver.get("index.baidu.com/v2/main/ind…"+ word +"?words="+ word)
#當你開啟無頭瀏覽器時,你需要操作一下瀏覽器,可以移動瀏覽器位置,放大或縮小瀏覽器,否則網站會判定你是爬蟲
#在此,我先等待了1秒,然後放大瀏覽器,然後縮小瀏覽器,然後等待2秒
time.sleep(1)
driver.set_window_size(1200, 800)
time.sleep(1)
driver.set_window_size(1000, 800)
time.sleep(2)
#等待2秒以後輸入使用者名稱和密碼
#先獲取使用者名稱和密碼的輸入框
getUserPhoneDom = driver.find_element_by_id('TANGRAM__PSP_4__userName')
getUserPassDom = driver.find_element_by_id('TANGRAM__PSP_4__password')
#輸入使用者名稱和密碼的時候不能夠一下將使用者名稱全部輸入,否則網站會判定你是爬蟲,就會讓你輸入簡訊驗證碼
#此處我按照字元輸入,並且每個字元輸入時,間隔400毫秒
for i in phone:
getUserPhoneDom.send_keys(i)
time.sleep(.4)
#密碼的輸入同使用者名稱的輸入是一個道理
for j in password:
getUserPassDom.send_keys(j)
time.sleep(.4)
#輸入完使用者名稱和密碼以後間隔1秒再點選登入按鈕
time.sleep(1)
#點選登入按鈕
action=ActionChains(driver)
loginDom = driver.find_element_by_id('TANGRAM__PSP_4__submit')
action.move_to_element(loginDom).click().perform()
#網站在登入的時候會偶爾出現驗證碼,此處是為了判斷是否出現驗證碼,如果出現就重新執行函式
time.sleep(2)
try:
errorData = driver.find_element_by_id('TANGRAM__PSP_4__error').text
if errorData == "請您輸入驗證碼":
login(word, phone, password)
except:
pass
複製程式碼
login(word, phone, password)
#此處是為了讓開啟的瀏覽器進行一直執行不關閉,以便於後面使用
root = Tk()
root.withdraw()
root.mainloop()
複製程式碼