網絡爬蟲,是一個自動提取網頁的程序,它爲搜索引擎從萬維網上下載網頁,是搜索引擎的重要組成。
可是當網絡爬蟲被濫用後,互聯網上就出現太多同質的東西,原創得不到保護。
因而,不少網站開始反網絡爬蟲,千方百計保護本身的內容。
他們根據ip訪問頻率,瀏覽網頁速度,帳戶登陸,輸入驗證碼,flash封裝,ajax混淆,js加密,圖片等技術,來應對網絡爬蟲。
防的一方不惜成本,迫使抓的一方在考慮成本效益後放棄。
抓的一方不惜成本,防的一方在考慮用戶流失後放棄。python
User-Agent 是HTTP協議的中的一個字段, 其做用是描述發出HTTP請求的終端的一些信息。使得服務器可以識別客戶使用的操做系統及版本、CPU類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。服務器經過這個字段就能夠知道訪問網站的是什麼人。對於不是正常瀏覽器的用戶進行屏蔽。web
解決方案: 假裝瀏覽器的User-Agent,由於每一個瀏覽器的User-Agent不同,而且全部的用戶都能使用瀏覽器。全部每次請求的時候條件瀏覽器的User-Agent,就能解決UA檢測。ajax
Referer 是header的一部分,當瀏覽器向web服務器發送請求的時候,通常會帶上Referer,告訴服務器我是從哪一個頁面連接過來的。例若有一些圖片網站在你請求圖片的時候,就會檢測你的Referer值,若是Referer不符合,不會返回正常的圖片。算法
解決方案:在檢測referer的請求中,攜帶符合的referer值。瀏覽器
所謂 JavaScript 混淆,基本就是:
1.去掉一些實際沒有調用的函數。
2.將零散的變量聲明合併。
3.邏輯函數的精簡。
4.變量名的簡化。具體要看不一樣的壓縮工具的考慮優劣。常見的有UglifyJS、JScrambler等工具。安全
js渲染其實就是對HTML頁面的修改。好比有一些網頁自己沒有返回數據,數據是通過js加載以後添加到HTML當中的。當遇到這種狀況的時候,咱們要知道爬蟲是不會執行JavaScript操做。因此須要用其餘的方法處理。服務器
解決方案:
1.經過閱讀網站js源碼,找到關鍵的代碼,並用python實現。
2.經過閱讀網站js源碼,找到關鍵的代碼,用PyV8等庫直接執行js代碼。
3.經過selenium庫直接模擬瀏覽器環境。網絡
WEB系統都是走http協議跟WEB容器連通的,每次請求至少會產生一次客戶端與服務器的tcp鏈接。對於服務端來講能夠很清楚的查看到,一個ip地址在單位時間內發起的請求。當請求數超過必定的值以後,就可判斷爲非正常的用戶請求。dom
解決方案:
1.自行設計ip代理池,經過輪換的方式,每次請求攜帶不一樣的代理地址。
2.ADSL動態撥號他有個獨有的特色,每撥一次號,就獲取一個新的IP。也就是它的IP是不固定的。tcp
驗證碼(CAPTCHA)是「Completely Automated Public Turing test to tell Computers and Humans Apart」(全自動區分計算機和人類的圖靈測試)的縮寫,是一種區分用戶是計算機仍是人的公共全自動程序。能夠防止:惡意破解密碼、刷票、論壇灌水,有效防止某個黑客對某一個特定註冊用戶用特定程序暴力破解方式進行不斷的登錄嘗試。
這個問題能夠由計算機生成並評判,可是必須只有人類才能解答。因爲計算機沒法解答CAPTCHA的問題,因此回答出問題的用戶就能夠被認爲是人類。
解決方案:
1.手動識別驗證碼
2.pytesseract識別簡單的驗證碼
3.對接打碼平臺
據記載,公元前400年,古希臘人發明了置換密碼。1881年世界上的第一個電話保密專利出現。在第二次世界大戰期間,德國軍方啓用「恩尼格瑪」密碼機,密碼學在戰爭中起着很是重要的做用。
隨着信息化和數字化社會的發展,人們對信息安全和保密的重要性認識不斷提升,因而在1997年,美國國家標準局公佈實施了「美國數據加密標準(DES)」,民間力量開始全面介入密碼學的研究和應用中,採用的加密算法有DES、RSA、SHA等。隨着對加密強度需求的不斷提升,近期又出現了AES、ECC等。
使用密碼學能夠達到如下目的:
保密性:防止用戶的標識或數據被讀取。
數據完整性:防止數據被更改。
身份驗證:確保數據發自特定的一方。
加密算法分類
根據密鑰類型不一樣將現代密碼技術分爲兩類:對稱加密算法(祕密鑰匙加密)和非對稱加密算法(公開密鑰加密)。
對稱鑰匙加密系統是加密和解密均採用同一把祕密鑰匙,並且通訊雙方都必須得到這把鑰匙,並保持鑰匙的祕密。
非對稱密鑰加密系統採用的加密鑰匙(公鑰)和解密鑰匙(私鑰)是不一樣的。
對稱加密算法主要包含DES、3DES、AES等算法。
非對稱加密算法主要包含RSA、DSA、ECC等算法
DES:
全稱爲Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法
入口參數有三個:Key、Data、Mode
Key爲7個字節共56位,是DES算法的工做密鑰;
Data爲8個字節64位,是要被加密或被解密的數據;
Mode爲DES的工做方式,有兩種:加密或解密
3DES(即Triple DES)是DES向AES過渡的加密算法,
使用兩個密鑰,執行三次DES算法,
加密的過程是加密-解密-加密
解密的過程是解密-加密-解密
AES:
高級加密標準(英語:Advanced Encryption Standard,縮寫:AES),這個標準用來替代原先的DES
AES的區塊長度固定爲128 比特,密鑰長度則能夠是128,192或256比特 (1六、24和32字節)
大體步驟以下:
一、密鑰擴展(KeyExpansion),
二、初始輪(Initial Round),
三、重複輪(Rounds),每一輪又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,
四、最終輪(Final Round),最終輪沒有MixColumns。
RSA:
公鑰加密算法,一種非對稱密碼算法
公鑰加密,私鑰解密
3個參數:
rsa_n, rsa_e,message
rsa_n, rsa_e 用於生成公鑰
message: 須要加密的消息
PyCrypto是Python中密碼學方面最有名的第三方軟件包。惋惜的是,它的開發工做於2012年就已中止。其餘人還在繼續發佈最新版本的PyCrypto,若是你不介意使用第三方的二進制包,仍能夠取得 Python 3.5 的相應版本。好比,能夠在 Github 上找到了對應 Python 3.5 的 PyCrypto 二進制包。
幸運的是,有一個該項目的分支 PyCrytodome 取代了 PyCrypto 。爲了在 Linux 上安裝它,你可使用如下 pip 命令:
pip install pycryptodome
在 Windows 系統上安裝則稍有不一樣:
pip install pycryptodomex
位:比特,就是計算機裏面的0或1
計算機最小的存儲單位:字節(byte)
一個字節有8位(比特)
binascii庫
a2b_hex :16進制轉bytes
b2a_hex :把bytes字符串轉16進制
a2b_base64 :把ascii字符轉成二進制
b2a_base64 :把二進制轉成ascii字符
DES加密實例
from Cryptodome.Cipher import DES import binascii def pad(text): while len(text)%8 != 0: #不是8的倍數,用空格補全成8的倍數 text += ' ' return text # 或者 # def pad(text): # text = text.encode() # result = len(text) %8 # if ( result != 0): #當字節數不是8的倍數時,用\0字節補全 # text = text + (b'\0'*(16-result)) # return text key = b'abcdefgh' # 密鑰,通常是8位或16位 des = DES.new(key,DES.MODE_ECB) #參數 key:密鑰 mode:模式通常是DES.MODE_ECB text = 'hello world' #要加密的文本 encrypto_text = des.encrypt(pad(text).encode()) # 加密 print('密文',binascii.b2a_hex(encrypto_text)) #把bytes轉成16進制 # 若是不通過pad處理,會報錯 :加密的數據不對,必須是密鑰的位數的整數倍(此處是8的整數倍) data = des.decrypt(encrypto_text).rstrip() # 會多出來一些字符串,因此要rstrip一下 print('明文',data)
>>
密文 b'c720e6acbf9f18b072b2abe014f5a6ce' 明文 b'hello world'
AES加密實例
from Cryptodome.Cipher import AES from binascii import a2b_hex,b2a_hex class aescrypt(): def __init__(self,key): self.key = key.encode() #傳入公鑰 self.mode = AES.MODE_ECB #選定模式 self.aes = AES.new(self.key,self.mode) #建立一個aes對象 #這裏的密鑰長度必須是1六、24或32,目前16位的就夠用了 def aesencrypt(self,text): # 用公鑰加密數據,獲得密文,並轉成16進制 # text = text.encode() # result = len(text) %16 # if ( result != 0): #當字節數不是16的倍數時,用\0字節補全 # text = text + (b'\0'*(16-result)) # self.encrypt_text = self.aes.encrypt(text) while len(text) % 16 !=0: #當須要加密的字符串長度不是16的倍數,在後面添加空格直到是16的倍數爲止 text = text + ' ' self.encrypt_text = self.aes.encrypt(text.encode()) return b2a_hex(self.encrypt_text) def aesdecrypt(self,text): # 把密文轉成字符串,而後用公鑰解密,去掉多餘的空格 self.decrypt_text = self.aes.decrypt(a2b_hex(text)) return self.decrypt_text.decode().rstrip(' ') if __name__ == '__main__': pr = aescrypt('abcdefghabcdefgh') en_text = pr.aesencrypt('hello world') print('密文:',en_text) de_text = pr.aesdecrypt(en_text) print('明文:',de_text) >> 密文: b'10ccb47c783a235845b23d23ce68c4f2' 明文: hello world
RSA加密實例
import rsa from binascii import a2b_hex,b2a_hex class rsacrypt(): def __init__(self): self.pub_key,self.priv_key = rsa.newkeys(1024)# 生成公鑰和私鑰 def rsa_encrypt(self,text): self.encrypt_text = rsa.encrypt(text.encode(),self.pub_key)# 此時是bytes return b2a_hex(self.encrypt_text) # 轉成16進制密文 def rsa_decrypt(self,text): self.decrypt_text = rsa.decrypt(a2b_hex(text),self.priv_key) # 把16進制密文轉成bytes,而後解密 return self.decrypt_text.decode() if __name__ == '__main__': rs = rsacrypt() text = "hello world" en_text = rs.rsa_encrypt(text) print('密文:',en_text) de_text = rs.rsa_decrypt(en_text) print('明文:',de_text) >> 密文: b'0ecaa6c11e95d1f720ae22d4d80280aa3f28052072773f608bba2c80ee93dfc9cbd5d47c76134c6fec0c26398807b0836e221fdb28eb20bee2d676ebb2c37671c926e11109aa19e1f1ee9e3f2e37e5218b0452390878a4d2aa557aa278462691ff08eababbd02707d7be8e25f6e6b814a88b107f56f8afbb6b7c4d14e9352808' 明文: hello world
補充:
MD5消息摘要算法(英語:MD5 Message-Digest Algorithm),一種被普遍使用的密碼散列函數,能夠產生出一個128位(16字節)的散列值(hash value),用於確保信息傳輸完整一致
import hashlib s = 'hello world' m = hashlib.md5() # 實例 m.update(s.encode()) # 加密的數據都是bytes類型 print(m.hexdigest()) # 加密後以16進制展現 >> 5eb63bbbe01eeed093cb22bb8f5acdc3
Base64是網絡上最多見的用於傳輸8Bit字節碼的編碼方式之一,Base64就是一種基於64個可打印字符來表示二進制數據的方法。
原理
用64個字符來表示二進制數據的方法
A-Z a-z 0-9 + /
把3個字節(24位)的二進制數據進行拼接,按照6位進行分割,變成4個字節,若是二進制數據不能被3整除,餘1個字節則在末尾有1個=,餘2個字節則在末尾有2個=
轉碼過程例子:
3*8=4*6
內存1個字節佔8位
轉前: s 1 3
先轉成ascii:對應 115 49 51
2進制: 01110011 00110001 00110011
6個一組(4組) 011100110011000100110011
而後纔有後面的 011100 110011 000100 110011
而後計算機是8位8位的存數 6不夠,自動就補兩個高位0了
全部有了 高位補0
科學計算器輸入 00011100 00110011 00000100 00110011
獲得 28 51 4 51
查對下照表 c z E z
以「迅雷下載」爲例: 不少下載類網站都提供「迅雷下載」的連接,其地址一般是加密的迅雷專用下載地址。
其實迅雷的「專用地址」也是用Base64"加密"的,其過程以下:
1、在地址的先後分別添加AA和ZZ
2、對新的字符串進行Base64編碼
另: Flashget的與迅雷相似,只不過在第一步時加的「料」不一樣罷了,Flashget在地址先後加的「料」是[FLASHGET]
而QQ旋風的乾脆不加料,直接就對地址進行Base64編碼了
實例
import base64 s = 'hello world' r1 = base64.encodebytes(s.encode()) #編碼 print(r1) #每57個字節有一個\n r2 = base64.b64encode(s.encode()) # 若不想有\n分隔,用b64encode print(r2) data = base64.b64decode(r1) # 解碼 print(data) >> b'aGVsbG8gd29ybGQ=\n' b'aGVsbG8gd29ybGQ=' b'hello world'