常常在簡書上寫做,寫完後再發布到其餘網站,很是麻煩,因此準備搞一下自動發佈文章的工具。那麼第一步先要模擬登錄幾個網站。今天先從知乎開始。python
Python:python3.6 IDE:pycharm 抓包工具:Charles 系統環境:Mac 瀏覽器:Chrome
首先進行網站登陸抓包,打開Chrome瀏覽器無痕窗口,而後清空全部緩存,打開Charles,在Chrome瀏覽器地址欄輸入www.zhihu.com,打開知乎登陸界面
web
我是手機號登陸,郵箱沒有試過,不知道請求流程是否同樣,輸入帳號密碼,若是須要驗證碼的話會自動出現驗證碼輸入框,登陸成功後chrome
通常狀況下咱們能夠輸錯一次密碼或者驗證碼,來多看看請求流程。另外我用chrome瀏覽器抓取了好幾回登陸流程,發現都不同。因此最後就是綜合了一下幾回抓包的信息進行分析了。json
登陸請求通常是POST,這個不多有例外,有些網站通常會是第一個post請求,但是知乎的post請求有點頗多,這個請求中有username和password,那咱們就以這裏爲基準開始分析。看一下紅框中出現了兩個Authentication和Multipart,在其餘的登陸網站中我還沒碰到過這種狀況,這個Multipart好像以前的Form,Authentication應該是一種認證。api
先搜了一下這個Authentication信息
瀏覽器
看到是在main.app.xxxxx.js腳本中,打開腳本看一下,基本上是固定值,其實經過屢次請求能夠發現這個值是固定的。同時咱們能夠肯定其餘的一些固定參數。看過我以前文章的同窗應該知道,肯定參數最簡單的方式就是屢次請求觀察,很容易就能肯定固定值。緩存
經過觀察只有signature參數比較麻煩,timestamp是時間戳,captcha是咱們輸入的驗證碼,那麼搞定這個參數咱們就離成功很近了,爲何是很近而不是成功?這個咱們得記住,通常在分析請求的時候參數只是一部分,咱們要關注headers、cookies、提交參數。首先參數咱們確認了只須要分析signature。那麼再來看看headers微信
這裏有兩種抓包狀況,針對這種狀況要單獨分析,咱們接下來再分析。
而後再說說cookies,有時候咱們並不須要一開始就分析cookies,並且不是cookies中的每一項都是必須的。咱們先把cookies信息截取出來。後面再分析cookie
這裏咱們先分析提交參數signature。首先在charles中查詢參數值session
沒搜到,這種通常都是經過計算生成的,搜不到很正常。既然搜不到值,那咱們來搜一下參數名。
看一下搜索結果,main.app.xxxx.js中的比較像
其餘的參數也出如今這裏,那基本就是這個地方了。仔細觀察一下,SHA-一、setHMACKey、幾個update、getHMAC,第一反應是sha1加密,經過固定字符串+grantType+clientId+com.zhihu.web+時間戳進行加密,結果試了一下好像不是。度娘了一下HMAC / sha1,原來還有這種操做,OK這個參數搞定了,貼下代碼。
在抓包請求中咱們能夠看到,驗證碼請求應該是https://www.zhihu.com/api/v3/oauth/captcha?lang=en,在有些抓包結果中後面的lang=cn,不知道這倆是怎麼區分的。
咱們看到這個請求有三種訪問方式,GET、PUT、POST,分別看一下結果。
GET請求訪問結果會顯示是否須要輸入驗證碼。
PUT請求的返回值是圖片的base64加密數據。獲得base64數據後轉換爲圖片顯示便可
import base64 imgdata = base64.b64decode(result.get("img_base64")) with open("cap.png", "wb") as fp: fp.write(imgdata)
POST請求會返回驗證碼驗證結果。
經過圖15的截圖(固然POST返回錯誤是我故意輸錯驗證碼的結果)咱們知道驗證碼並非在登陸請求的時候才進行驗證的,須要提早驗證。
authorization的值和client_id值相等,那就都是固定值,不用管了。X-Xsrftoken:先搜一下這個值
在上面的請求response中設置的cookies值,那咱們直接從cookies中拿出_xsrf值,設置到headers中便可
X-UDID:跟X-Xsrftoken同樣,也是在cookies中設置的
拆分一下便可
既然咱們須要取cookies中的_xsrf和d_c0的值,那麼就得保證cookies中必須有這個值,稍微往上翻一下能夠看到Set Cookie在最初訪問www.zhihu.com中設置的
那麼訪問一下首頁就能夠了。分析到這裏就差很少了。接下來就是發送請求了。
這種表單也沒提交過,有點懵逼。可是看起來跟這個Content-Type: multipart/form-data有關係,請求發送類型。搜一下requests multipart
,找到一個請求庫requests_toolbelt,使用方式以下:
from requests_toolbelt import MultipartEncoder data = { "client_id":"xxxx", "grant_type":"password" } boundary = "----WebKitFormBoundaryJKBWBR54EIz5oTAY" encode_data = MultipartEncoder(data, boundary=boundary) headers["Content-Type"] = encode_data.content_type requests.post(url, data=encode_data.to_string())
這裏有個boundary須要關注一下,首先幾回請求的boundary信息不同,那確定是不同的,因此我大概搜了一下boundary這個值,沒發現這個值。度娘了一下WebKitFormBoundary,好像說這個boundary其實不發送也沒什麼關係。主要是我剛開始寫的時候這個boundary默認是空的,結果居然登陸成功了。我以爲既然值是隨意的,那麼有總歸比沒有好點吧,防止被ban碼。WebKitFormBoundary後面那16位大概是大小寫字母和數字隨機吧。那我就僞造了一下。
def random_boundary(): factor = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" boundary = "----WebKitFormBoundary{}".format("".join(random.choices(factor, k=16))) return boundary
好啦,這回算是全都搞定了,最後要驗證一下登陸是否成功,訪問一下我的中心便可:https://www.zhihu.com/people/wan-rou-2
最後咱們總結一下登陸過程:
def get_captcha(self): captcha = "" url = "https://www.zhihu.com/api/v3/oauth/captcha?lang=en" # 請求頭中增長Authorization self.session.headers["Authorization"] = "oauth c3cef7c66a1843f8b3a9e6a1e3160e20" r = self.session.get(url) result = r.json() if not result.get("show_captcha"): # 不須要輸入驗證碼 return "" else: while True: # 獲取驗證碼圖片base64 r = self.session.put(url) result = r.json() imgdata = base64.b64decode(result.get("img_base64")) with open("cap.png", "wb") as fp: fp.write(imgdata) im = Image.open("cap.png") im.show() captcha = input("輸入驗證碼>>") #驗證碼 boundary = self.random_boundary() cap_data = MultipartEncoder(fields={"input_text":captcha}, boundary=boundary) self.session.headers["Content-Type"] = cap_data.content_type # 發送驗證碼進行驗證 r = self.session.post(url, data=cap_data.to_string()) result = r.json() if not result.get("error", None): print("驗證碼正確") break else: # 驗證碼不正確,從新請求 print(result.get("error").get("message")) return captcha
若是你以爲個人文章還能夠,能夠關注個人微信公衆號:Python爬蟲實戰之路
也能夠掃描下面二維碼,添加個人微信號