github地址:ZhihuLogin
最近工(xian)作(de)不(dan)忙(teng), 一直寫Android沒意思, 于是就學習下python, 以下記錄我實現模擬知乎登錄的探索過程。
在開始之前, 我的個人習慣是先做好功課, 以下幾篇文章是我提前找的參考資料:
Python 爬蟲之模擬知乎登錄
零基礎自學用Python 3開發網絡爬蟲(四): 登錄
下面我就正式開始了。
首先我退出知乎賬號, 到知乎的登錄頁。
填上賬號密碼, 準備登錄, 但是當這個倒立的文字的驗證碼出來的時候, 我忽然意識到something went wrong。因為在我準備的“參考資料”中, 驗證碼還不是這種點擊倒立的文字,而是那種普通的需要填寫字母或者數字的驗證碼, 也就是說知乎的前端又改版了, 信息過時了, 之前的登陸方法也許就不能用了。不過我們還是繼續看看吧。
在我隨便點了幾個文字, 然后點擊登錄。因為我是隨便點的, 當然結果是驗證失敗。
然后我觀察到提交的表單數據是這樣的
email是登錄的郵箱賬號, password是密碼(我不會讓你看到的), 都是明文。
_xsrf是什么?在我事先準備的“參考資料”里說是一串偽隨機數, 是用來防止跨站請求偽造的。 什么意思呢?我也看不懂。 但是要得到這個值其實并不難,它其實隱藏在頁面的某個標簽中
然后用正則表達式或者beautifulSoup把這個值提取出來就行了,參考代碼:
def get_xsrf():
url = 'https://www.zhihu.com'
response = session.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'lxml')
# <input type="hidden" name="_xsrf" value="0448114b8b68c194d9fc9d831d251379">
tag = soup.find('input', attrs={'name': '_xsrf'})
return tag['value']
captcha_type是應該是一個常量值cn, 也不知道是不是必需的
captcha是一個字典, 應該就是點擊那張倒立的文字的圖片所生成的
字典中的"input_points":[[87.875,32]]應該是點擊的位置信息
然而這些信息我應該怎么得到呢?
我最終的答案是:得不到。
是的, 以我目前的作為一個python初學者并且對前端js什么的也一竅不通的水平來說, 我得不到。但是就這樣完了嗎?當然不(廢話不然我還寫這篇文章干嘛)。
雖然在電腦網頁端得不到這個input_points信息, 但是如果換成手機端的網頁, 就不會出現那種倒立的文字的驗證碼了, 以前的模擬登陸方式就又能用了
這種繞開倒立的文字的驗證碼的方式我是怎么想到的呢?其實我只是看了別人的代碼而已(不然我能怎么辦?)
參考自知乎上某位大佬的github上的代碼(https://github.com/xchaoinfo/fuck-login/blob/master/001%20zhihu/zhihu.py)
然后我也參考著寫了一份(其實跟大佬的代碼沒什么差別)
首先需要安裝然后導入這些包
import requests, time, os
from bs4 import BeautifulSoup
from http import cookiejar
接著定義一個全局的session, 用來保存和復用cookies。登錄之后獲取的cookies保存在本地的cookies.txt文件中, 下次需要登錄時再從中獲取cookies。為什么要復用cookies?因為這樣一次登陸之后你在瀏覽別的網頁你就不需要再次驗證身份了。關于session和cookies如果不是太清楚具體的可以看慕課網的這個教程, 我覺得講的挺好。
Requests庫-Session和Cookies
注意這里的user-agent也就是用戶代理要寫成手機端的, 比如這里是Android手機。
session = requests.session()
session.cookies = cookiejar.LWPCookieJar(filename='cookies.txt')
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36'
}
先判斷是否已經登陸, 也就是說先看看是否已經能夠查看自己的個人主頁的信息,如果可以,說明已經登陸了,那么接下來爬蟲就可以開始爬取信息了,如果不行,說明還需要重新登陸
def isLogin():
# 通過查看用戶個人信息來判斷是否已經登錄
url = "https://www.zhihu.com/settings/profile"
response = session.get(url, headers=headers, allow_redirects=False)
code = response.status_code
if code == 200:
return True
else:
return False
手機端網頁登陸時需要提交的表單參數有4個
data = {
'_xsrf': _xsrf,
'password': password,
'email': email,
'captcha': captcha
}
password和email是密碼和登陸的郵箱賬號,_xsrf上面也說過了。captcha是4位由字母和數字組成的驗證碼, 需要先將驗證碼圖片下載到本地, 然后人眼識別(是的你沒看錯)
def get_captcha():
t = str(int(time.time() * 1000))
captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
response = session.get(captcha_url, headers=headers)
with open('captcha.gif', 'wb') as f:
f.write(response.content)
os.startfile('captcha.gif')
return input('請輸入驗證碼: ')
上面那段代碼會在驗證碼圖片下載完成之后自動打開驗證碼圖片, 然后你觀察一下, 填上驗證碼。至于驗證碼圖片的鏈接地址的拼接方式是怎么得到的, 反正我是抄的。
然后就可以登陸了,記得登陸之后要把cookies保存下來, 這點非常重要, 因為這樣你打開知乎的別的網頁就不需要重新登陸了。
def login(email, password, _xsrf, captcha):
data = {
'_xsrf': _xsrf,
'password': password,
'email': email,
'captcha': captcha
}
login_url = 'https://www.zhihu.com/login/email'
response = session.post(login_url, data=data, headers=headers)
print('response.json() =', response.json())
# 保存cookies到本地
session.cookies.save()
效果演示和github地址(重要的事情再說一遍):ZhihuLogin
最后再說一點, 手機端登錄是怎么知道那幾個需要提交的參數的呢?應該是抓包, 但是知乎是https, https要怎么抓包?我找了一點資料https://www.zhihu.com/question/41751887
不過具體的我還沒有試過, 有問題歡迎一起討論