驗證碼執行流程

 本篇主要講述驗證碼的驗證流程,包括如何驗證碼的實現、如何獲取驗證碼、識別驗證碼(這篇是人來識別,機器識別放在下篇)、發送驗證碼。同樣以一個例子來說明。目標網址 http://icp.alexa.cn/index.php(查詢域名備案信息)

  1.驗證碼的實現:

  簡單的說,驗證碼就是一張圖片,圖片上有字符串。網站是如何實現的呢?有WEB基礎的人可能會知道,每個瀏覽器基本都有cookie,作爲這次回話的唯一標示。每次訪問網站,瀏覽器都會把這個cookie發送給服務器。驗證碼就是和這個cookie綁定到一起的。如何理解呢?舉個例子,現在有網站W,有A和B兩個人,同時訪問W,W給A返回的驗證碼是X,給B返回的驗證碼是Y,這兩個驗證碼都是正確的,但是如果A輸入了B的驗證碼,肯定驗證不通過。那服務器是怎麼區分A和B呢,就是用到的cookie。再舉個例子,有些網站你登錄一次之後,下次繼續訪問可能就自動登陸了,也是用cookie來標示唯一身份的,如果清除了cookie也就無法自動登陸了。cookie具體是什麼生成的,我們不必關心,只需要知道是一長串字符串就行了,你的和別人的都不一樣。(例子中的目標網址並不是用cookie,而是用的其他方式,所以可能會存在一些BUG)

  服務器後臺生成驗證碼的流程就很容易理解了:首先,生成一個隨機字符串,然後和cookie綁定,然後寫到圖片上返回給你。那麼,如何生成一個圖片驗證碼呢?下面是一個簡單的生成驗證碼源碼:

複製代碼

from PIL import Image
import ImageFilter,ImageDraw,ImageFont
import random

width = 80
height = 40
font = ImageFont.truetype('C:\\Windows\\Fonts\\AdobeFangsongStd-Regular.otf', 28)
image = Image.new("RGB",(width,height),(0,0,0))
draw = ImageDraw.Draw(image)
for t in range(4):
    draw.text((20*t,10),`random.randint(0,9)`,font=font,fill=(255,255,255))
image.show()

複製代碼

  代碼說明:

    a).PIL是python的圖片庫模塊,需要自己安裝

    b).ImageFont.truetype()是選擇字體

    c).Image.new("RGB",(width,height),(0,0,0))新建一個Image,背景色是白色((0,0,0)就代表的顏色),如果需要別的顏色,可自己查詢顏色代碼。window自帶的畫板就可以看到:

    

    d).random.randint(0,9)隨機數 範圍大於等於0,小於等於9

    e).draw.text((20*t,10),`random.randint(0,9)`,font=font,fill=(255,255,255),anchor=False) 第一個參數代表位置,帶二個代表內容,第三個代表字體,第四個代表字體顏色

    f).image.show()顯示圖片,第一詞會提示選擇默認圖片查看器。

   運行結果如下圖:

    

  2).驗證碼的獲取

    a).分析目標網站,可以看到當鼠標點擊驗證碼那個輸入框時會顯示驗證碼,如圖:

  

  那麼獲取驗證碼的請求是什麼?以及請求發送的時間?(驗證碼顯示的時間不一定是驗證碼獲取的時間,雖然這個例子中是,以爲驗證碼可能是頁面剛開始的時候一起加載的,只是一直被隱藏)。火狐瀏覽器F12打開控制檯,找到網絡標籤,刷新頁面,可以看到如下圖所示:

  

  並沒有發現獲取驗證碼的請求,那麼我們點擊驗證碼的那個輸入框,發現多了一個請求,沒錯,這就是獲取驗證碼的請求。

  

  b).下面我們開始分析這個請求,首先點擊這個請求,可以看到如下圖所示:

  

  完整URL:http://icp.alexa.cn/captcha.php?q=sina.com.cn&sid=82&icp_host=sxcainfo。可以看到三個參數:

  q=sina.com.cn:查詢的域名

  sid=82:這個ID暫時不知道是什麼,後面查看JS源代碼會看到

  icp_host:這個暫時也不知道。

  這三個參數,那些是必須的呢?可以一個一個測試。測試方法就是刪掉某個元素,然後再發請求。測試發現,三個參數缺省都可以獲取到驗證碼,獲取到驗證碼,不代表驗證碼可用,因爲,沒有與某些類似cookie的值綁定到一起,它就和圖片沒有任何區別,不具備驗證的功能。經我測試,(測試很簡單,不過要用到後面的東西,看完這篇,就知道怎麼測了),這三個參數都需要。在測試的過程中,我發現了sid就是一個隨機數,沒有什麼特殊含義,基本可以確定可以隨便輸入:js代碼如下:

  

  icp_host的取值有很多:sccainfo、ahcainfo、jscainfo......有沒有發現什麼規律?首先八個字母,最後六個都是cainfo,那麼前面兩個代表什麼?sc=四川、ah=安徽、js=j江蘇。所以,我們可以猜測這個是省份的簡寫。那這個值有什麼用呢?作用一,如果不按這個規則輸入字符串(比如,aaaaaaaa),就獲取不到驗證碼;作用二,驗證碼就是和這個綁定的。也就是說,你獲取驗證碼的時候用sccainfo,那麼驗證的時候也要用sccainfo。

  分析完參數,然後再分析請求頭,方法和參數的分析方法一樣,一個個刪除,看能不能獲取正確的結果。這個時候,可以自己寫python代碼測試,具體代碼如下:

複製代碼

#encoding=utf8
import urllib2
from PIL import Image
import cStringIO
getCode_url = "http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo"
header={"Referer":"http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo"}
# header['Host']="icp.alexa.cn"
# header['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"
header['Cache-Control']="max-age=0"
request = urllib2.Request(getCode_url,headers=header)
res = urllib2.urlopen(request).read()
image = Image.open(cStringIO.StringIO(res))
image.show()

複製代碼

  代碼說明:

    a).cStringIO python的流模塊,無論是圖片、文本、音頻、視頻都是流文件,可以相互轉化。這裏的作用是將圖片流還原成圖片

    b).header中添加參數可直接用header['']="",這樣就可以測試了。具體哪些參數必須,自己測試。

  運行結果:

  

  3).檢驗驗證碼

   a).分析目標網站,尋找檢驗驗證碼的請求。我們在輸入框輸入正確的驗證碼,點擊備案查詢,如圖所示:

    

    可以看到控制檯中多了一個請求

    

    點擊請求,查看請求詳情:http://icp.alexa.cn/index.php?q=163.com&code=65a89c&icp_host=lncainfo

    三個參數:

     q=163.com:查詢的域名,必不可少

     code=65a89c:驗證碼,必不可少

     icp_host=lncainfo:和獲取驗證碼相對應

    然後再分析header,與上面的方法一樣。這兩次檢驗不同的是:檢驗獲取驗證碼時,是自己寫代碼獲取驗證碼,然後放到網站上檢驗,驗證碼的正確性(必須保證icp_host一致);檢驗檢查驗證碼時,是用網站獲取驗證碼,填到代碼裏面,看看參數對不對。

    驗證代碼如下:

複製代碼

#encoding=utf8
import urllib2

checkcode_url = "http://icp.alexa.cn/index.php?q=163.com&code=N3PE37&icp_host=hncainfo"
header={}
# header['Pragma']="Pragma"
# header['Referer']="http://icp.alexa.cn/index.php?q=163.com&code=CUXWDV&icp_host=sccainfo"
header['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"
request = urllib2.Request(checkcode_url,headers=header)
res = urllib2.urlopen(request).read()
print res

複製代碼

 

    代碼說明:icp_host=hncainfo這個參數必須和你獲取驗證碼時候的參數一致

    運行結果:

  

    如果驗證碼不正確或者別的地方不一致,會返回:

    

  到此,我們就分析完了,不過現在是把獲取和驗證放在兩個代碼中運行,怎麼放在一起呢?代碼如下:

複製代碼

#encoding=utf8
import urllib2
from PIL import Image
import cStringIO
import BeautifulSoup

def getCode(domain):
    print "獲取驗證碼...."
    getcode_url="http://icp.alexa.cn/captcha.php?q="+domain+"&sid=0&icp_host=hncainfo"
    getcode_headers = {}
    getcode_headers['Referer']="http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo"
    getcode_headers['Cache-Control']="max-age=0"
    getcode_request = urllib2.Request(getcode_url,headers=getcode_headers)
    getcode_res = urllib2.urlopen(getcode_request).read()
    image = Image.open(cStringIO.StringIO( getcode_res))
    print "獲取驗證碼成功"
    image.show()
def checkcode(domain,code):
    # print "您輸入的驗證碼爲:"+`code`
    print "開始檢查驗證碼..."
    checkcode_url = "http://icp.alexa.cn/index.php?q="+domain+"&code="+code+"&icp_host=hncainfo"
    checkcode_headers={}
    checkcode_headers['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"
    checkcode_request = urllib2.Request(checkcode_url,headers=checkcode_headers)
    checkcode_res = urllib2.urlopen(checkcode_request).read()
    if(checkcode_res.count("主辦單位名稱")>0):
        print "驗證成功"
        checkcode_soup = BeautifulSoup.BeautifulSoup(checkcode_res)
        print "所屬單位名稱:"+checkcode_soup.findAll("table")[0].findAll("tr")[0].findAll("td")[1].text.encode("utf8")
    else:
        print "驗證失敗"
domain = raw_input("請輸入域名:")
getCode(domain)
code = raw_input("請輸入驗證碼:")
checkcode(domain,code)

複製代碼

    代碼說明:

      a).def getCode(domain) 聲明一個函數,getCode是函數名,domain是參數

      b).raw_input() 獲取用戶輸入

      c).在獲取和驗證的時候,我把icp_host都寫成了hncainfo,這樣就可以保證一致。

      d).encode("utf8") 對變量以utf8格式編碼

      e).驗證碼要人工識別輸入

    運行結果:

    

    

  到此,整個驗證碼的獲取,驗證都講述完了,驗證碼的識別放在下一節。

  說明:

  a).代碼僅供學習交流

  b).如有錯誤,多多指教

  c).轉載請註明出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章