JB的Python之旅-爬蟲篇-圖形驗證碼(3)-- 驗證碼的生成了解下

前言

最近在看怎麼繞過圖形驗證碼,雖然有思路,可是有點吃力,估計還要折騰幾天,內心就想吐槽:驗證碼真難搞的;
這不,既然如今還沒搞定驗證碼,那要不看看驗證碼是怎麼生成的?原理是怎麼處理的?
因而乎就有了此篇,寫的不是很好,求各大神指教下;
php

前幾天原本也想本身搞個網站,就去了解下備案是什麼鬼,而後就找到這麼一個網站:
http://icp.alexa.cn/index.phphtml

用來查詢備案的,這裏面也有驗證碼,那就用這個網站先玩玩吧; python

對了,這裏的驗證碼指的是圖形驗證碼web

流程

正常的流程:
驗證碼於服務器端生成,發送給客戶端,並以圖像格式顯示。
客戶端提交所顯示的驗證碼,客戶端接收並進行比較,若比對失敗則不能實現登陸或註冊,反之成功後跳轉相應界面;
api

若是真這麼簡單,是否是用窮舉的方式就能破解了?
瀏覽器

有web基礎的人可能會知道,每一個瀏覽器都會有cookie,是做爲此次回話的惟一標示;
服務器

cookie

防止有同窗不知道,先簡單介紹下cookie:
cookie

1. 什麼是Cookie,它的用途是什麼?
Cookies是一些存儲在用戶電腦上的小文件。
它是被設計用來保存一些站點的用戶數據,這樣可以讓服務器爲這樣的用戶定製內容,後者頁面代碼可以獲取到Cookie值而後發送給服務器。
好比Cookie中存儲了所在地理位置,之後每次進入地圖就默認定位到改地點便可。app

2. Cookie是何時生成的,完整的生成、傳遞和使用過程是怎麼樣的?
寫數據到Cookie中一般是在一個頁面被加載的時候,好比提交按鈕被按下,後臺處理完請求跳轉到相應頁面後會把Cookie值帶回來;
以下是一個例子:dom

  • 在瀏覽器地址欄輸入了一個站點,而後瀏覽器會發送請求到站點的Web服務器請求該頁面
  • 與此同時,瀏覽器會在我的電腦上行查找和該站點對應的Cookie文件,若是發現了就會把裏面的鍵值對內容所有發送給Web服務器,若是沒找到則不發送。
  • 頁面服務器接收到了Cookie的數據後,能夠利用這些數據決定返回到前臺的內容
  • 若是沒鍵值對被Web服務器接收到,站點就知道該用戶沒有訪問過,就會爲這個訪問地址新建一個ID而且發送一些鍵值對給前臺,這些值會被放在此次響應中的Header帶給瀏覽器,瀏覽器端因而有了Cookie的值
  • 任何到服務的訪問和數據請求均可能很對Cookie中的鍵值對進行修改

實現

大體瞭解下cookie,不至於那麼不清不楚;那就繼續拉;

通常來講,每次訪問網址,瀏覽器都會把cookie發送給服務器,而驗證碼就是和這個cookie綁定在一塊兒的;
舉個例子:

  • 如今有網址T,有用戶A和B兩我的同事訪問T
  • T給A返回的驗證碼是X,給B返回的驗證碼是Y,這兩個驗證碼都正確
  • 若是A輸入B的驗證碼,是驗證不經過的

那服務器怎麼區分A和B?那就是用cookie;

cookie是標示惟一身份的,好比有些網站,登陸一次後會自動登陸,可是若是清除了cookie,就沒法自動登陸了,並且這cookie是個別人不同的;

說到這裏,服務器後臺生成驗證碼的流程就很容易理解了:

  • 先隨機生產一個隨機字符串
  • 而後和cookie綁定
  • 再寫到圖片上返回給你

那,怎麼生成一個圖片驗證碼?

生成圖片驗證碼

from PIL import Image,ImageDraw,ImageFont
#PIL是python的圖片庫模塊
import random
#隨機函數

width = 80
height = 40
font = ImageFont.truetype('C:\\Windows\\Fonts\\STFANGSO.ttf', 28)
#選擇字體
image = Image.new("RGB",(width,height),(120,10,200))
#新建一個Image,背景色是黑色(000),若是須要別的顏色,本身修改便可;圖片大小就是開始定義的80X40
draw = ImageDraw.Draw(image)
#建立一個能夠在給定圖像上繪圖的對象
for t in range(4):
    #4是表明幾位,須要須要4位數字的驗證碼,這裏輸入4,須要10位,就10
    draw.text((20*t,10), repr(random.randint(0, 9)), font=font, fill=(255, 255, 255))
    #random.randint(0, 9),隨機數,0-9
    #第一個參數表明位置,第二個表明內容,第三方表明字體,第四個表明字體顏色
image.show()
#顯示圖片
複製代碼

效果圖:

驗證碼就這樣生成啦~

驗證碼的獲取

回到一開始的網站:http://icp.alexa.cn/index.php

打開後發現,網頁自動就顯示驗證碼了,有辦法獲取到這個驗證碼嗎?F12刷新一波試試

有一個這樣的請求,點擊後的確就是驗證碼的圖片了;

連接以下:
http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=f419510445e39e61cc32a7efd7552ed1&R=0.37766116804135375

從連接分析,有3個參數:

  • host=hcainfo
  • flag = f419510445e39e61cc32a7efd7552ed1
  • R=0.37766116804135375

嗯,一臉懵逼,看不懂,先無論,咱們來測試下,看看這3個參數哪一個是必須的;
怎麼測試?簡單,直接copy上面的url,在瀏覽器打開,而後一個個參數刪除,如:

  • http://www.alexa.cn/api/icp/vcode?host=gxcainfo&flag=8f7e4e73eb36c20033ed825238266823
  • http://www.alexa.cn/api/icp/vcode?host=gxcainfo
  • http://www.alexa.cn/api/icp/vcode
  • http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=&R=

還能夠多試試排列組合,最終得出一個結論:host=gxcainfo是必須的,flag跟R不是必須的,空或者沒有參數,都不影響獲取驗證碼;

可是,能獲取到驗證碼,不表明該驗證碼是可用的,由於若是沒有與某些相似cookie的東西綁定在一塊兒的話,那它自己就只是圖片而已,沒特殊含義,也不具有驗證功能;

那host的值呢?嘗試了一下,把host的值改爲其餘亂七八糟的,也同樣獲取不到驗證碼,這裏面啥狀況;

把網頁刷新,每次刷新,host的值都在變化,好比ahcainfo、gxcainfo、ecainfo,若是不刷新網頁,host的值則一直不變;
經過上面3個host的值,發現一點疑問,都是8個字母,並且後面六位都是cainfo,只有前面兩個在變;ah\gx,給人感受就是安徽跟廣西?可是ec想不出,怎麼感受,有點像省份的意思?
親自試了下,修改爲gd,hn也能獲取到驗證碼,莫非真是省份?那ec是啥??

這裏繼續猜就沒意義了,但可知的是:
1)沒有host這個值就獲取不到驗證碼;
2)及時有host,值不對也是獲取不到驗證碼;
3)那是否是說明,驗證碼是跟這個值綁定的?

url參數就到這裏了,接下來請求頭吧~
沒太特別,直接把整個請求頭copy過來用就好了:

import requests
from PIL import Image
import io

getCode_url = "http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=f419510445e39e61cc32a7efd7552ed1&R=0.37766116804135375"
header = {
    "Referer":"http://icp.alexa.cn/",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
}

response = requests.get(getCode_url,headers=header).content
image = Image.open(io.BytesIO(response))
image.show()
複製代碼

這上面的代碼,好像沒什麼特別,應該不須要說明的;

運行的結果就是:

總體的代碼:

import requests
from PIL import Image
import io

def getCode(url):
    print("獲取驗證碼")
    getCode_url = "http://www.alexa.cn/api/icp/vcode?host=jlcainfo&flag=61684048f21350aa2767b82315a0f487&R=0.5917477648057996"
    header = {
        "Referer":"http://icp.alexa.cn/",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
    }

    response = requests.get(getCode_url,headers=header).content
    image = Image.open(io.BytesIO(response))
    print("獲取驗證碼成功")
    image.show()

def checkcode(url,code):
    print("開始檢查驗證碼")
    checkcode_url = "http://www.alexa.cn/home/index/query?token=1a63a83b2xwDdXlEmmIldi-Cx729izemOE54BDjY8jnT-JCvU3Atg0W1gCrBVbMSs-O&flag=61684048f21350aa2767b82315a0f487&host=jlcainfo&flag&domain=qq.com&type=icp&type=icp&vcode="+code
    header = {
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding":"gzip, deflate",
        "Accept-Language":"zh-CN,zh;q=0.9",
        "Connection":"keep-alive",
        "Cookie":"SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; exi_query_history=nseyfqfp4SgNKMagNO-DctlkEDqameDvLLDbwUIuYCiHNkoLJPniHTUs0RIAq5jNEZ8ojjeoe8W8y1Df6vuMiy8r-H37690i99d0LZ3iyTWMVmstIOcGqb5H-DY1k2Gn3FNdj02TwpVtlca1b1lrvrdSfE-HbUGwP3Lfex0D9Hzeu48-N",
        "Host":"www.alexa.cn",
        "Referer":"http://icp.alexa.cn",
        "Upgrade-Insecure-Requests":"1",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
    }
    response = requests.get(checkcode_url,headers=header)
    print(response.content)
    print(response.status_code)


if __name__ == "__main__":
    getCode("qq.com")
    code = input("請輸入驗證碼:")
    checkcode("qq.com",code)
複製代碼

原本是想弄個,自動拉取驗證碼圖片,手動輸入後自動拉取結果,可是執行的時候,仍是被網站識別出來了,想了好久還沒想明白,算了留下了一個爛攤子吧~

小結

本文主要介紹了驗證碼是怎麼生成的,原本也想結合作個機器識別的,但在調試過程,依然被網站識別出來了,折騰半天,目前無果,先棄療,後面想到緣由再來更新吧~

謝謝你們~

相關文章
相關標籤/搜索