@(博客)[Python, 登錄, 知乎, 爬蟲]python
018.8.12git
由於學年綜合實踐準備的一部分須要爬取知乎全站,因此爲了方便,自動登錄是頗有必要的。而因爲許多學習爬蟲的各友,都愛拿知乎練手——其實我倒非然,這算是第一次對知乎「開戰」,是客觀因素致使的必然——以致於知乎增強了反扒機制
github
我爬蟲經驗有限,實在不知該對這樣的加密如何下手,一番搜索引擎以後,獲得的都是過時操做。Github上找到了經過二維碼掃描登錄的思路,那就以此宣戰吧。chrome
也在此感謝這名網友的無私奉獻,點擊可查看json
說句題外話:切不能夠慣性思惟api
另:完整代碼已上傳Github,文章末尾有連接。裏邊的study文件是我整個思考過程當中產生的測試代碼,若是隻是須要實現知乎登錄,則study文件能夠直接刪除瀏覽器
(1)python3.6
(2)主要第三方庫:
- requests
- PIL
:pip3 install -i https://pypi.douban.com/simple/ pillow
利用豆瓣源,加快下載速度,由於直接安裝可能會出現timeout的錯誤cookie
(3)chromesession
第一步確定是先來到知乎提供二維碼登錄的界面,利用開發工具,可查看請求這個二維碼圖片須要那些數據
工具
能看到是get請求,headers也很尋常,但屢次刷新可發現請求的url地址有一部分在改變
這確定算不上什麼難點,咱們尋找前面的文件,能找到這部分動態改變的值
爲了方便闡述,那就把image稱之爲A文件,qrcode成爲B文件。這裏就有了一個思路,先請求B文件,拿到token值之後,拼接成目的url,再去請求A文件
因而咱們從A遷移到了B
可見請求B文件的時候,headers字段是真的不少,但絕對不會全部都必要,這隻能排除法了
以我拙見是這樣處理的,首先看清楚了,是POST請求(從爬蟲到如今也幾個月了,仍是爬了很多網站,真的不提交數據用post請求的,我第一次見,因此以前一直是慣性思惟的用get,而後一直請求失敗, 因此各位入門爬蟲的注意了,千萬注意了別掉坑裏)
複製了全部headers,作一次post的請求,再看看狀態碼是否是201(爲了不請求被重定向,建議打印請求內容,或者關閉重定向,後面皆以打印內充處理再也不單獨提示)(對應study/test1.py文件)
能夠說很OK,而後就開始排除法,首先去掉的是最經常使用不到的噻。經過幾輪排除下來,發現Cookie和User-Agent是必要的,既然須要用到cookie,咱們就得維持會話,因此要實例化一個session對象了,實現以下:
session = requests.session()
順便也把Cookie分解了,看看須要哪些內容
for item in headers["Cookie"].split(";"):
print(item.split("=")[0])
(這些很重要,可得記住了)
那麼如何讓session對象持有完整的cookie呢?
咱們回到最初的起點,再來分析一下完整的過程
打開開發者工具,刷新頁面,而後點擊二維碼登錄(固然,這裏建議你清除一下cookies,最好選擇【高級】而不是【基本】)
咱們能夠看到第一次請求登錄界面的時候,請求是不帶cookies的;而請求以後,按照響應體的要求,會設置對應的_xsrf,_zap,tgw_17。前面咱們知道須要6個,這裏才三個確定是不夠的,因此繼續找signin後面的文件,看看到底有什麼貓膩在裏頭
因而在udid這個文件中,你會發現響應體要求設置q_c1,d_c0;也就是說,在成功請求這個文件以後,Cookie就包含這兩個部分了
照例複製下完整的headers,找到請求的url,以及請求方式(注意了!這裏也是post),最後排除法,找到必要的部分(對應study/test2.py文件)
仍然是Cookie以及User-Agent
還不夠,如今咱們的cookies還差capsion_ticket部分,因此繼續擼
因而找到了captcha?lang=cn文件,它的響應體告訴瀏覽器,能夠設置capsion_ticket了
(對應study/test3.py文件)
有了這波分析,咱們就能夠開始動手敲代碼了
(對應studyget-qrcode.py文件)
import requests
session = requests.session()
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 \ (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
}
# 第一次請求,爲了Cookie(_xsrf,_zap,tgw_17)
session.get(url="https://www.zhihu.com/signin", headers=HEADERS)
# 第二次請求,爲了Cookie(q_c1,d_c0)
session.post(url="https://www.zhihu.com/udid", headers=HEADERS)
# 第三次請求,爲了Cookie(capsion_ticket)
session.get(url="https://www.zhihu.com/api/v3/oauth/captcha?lang=cn", headers=HEADERS)
# 第四次請求,爲了token,用於構建二維碼圖片的請求連接
response = session.post(url="https://www.zhihu.com/api/v3/account/api/login/qrcode", headers=HEADERS)
# print(response.json())
# 第五次請求,爲了二維碼圖片
url4QR = "https://www.zhihu.com/api/v3/account/api/login/qrcode/{0}/image".format(response.json().get("token"))
response = session.get(url=url4QR, headers=HEADERS)
if response.status_code == 200:
with open("qr.jpg", "wb") as file:
file.write(response.content)
print("【保存二維碼成功】")
else:
print("【請求二維碼圖片錯誤】")
運行結果以下
這時候覺得掃描二維碼就登錄成功了嗎?然而沒有
咱們掃描一下網頁的二維碼登錄一下試試,會發如今手機上點擊確認登錄之後,請求知乎www.zhihu.com
網頁的時候,Cookie又多了一個z_c0
暈!可是扶住牆,老規矩。能夠看到距離知乎首頁文件最近的一個scan_info文件,說了要設置z_c0
因而在咱們掃描二維碼以後,應該先請求這個文件,再請求首頁文件;查看請求的url,也能發現,這個文件也有一部分是動態的,並且正是以前獲取的token
爲了確保咱們成功登錄,可測試編輯頁面,由於這個頁面只有在登錄成功後能夠訪問,否則就會被重定向到登錄頁面去
添加代碼以下
# 阻塞程序,給予用戶掃描二維碼的時間
input("請隨便輸入後回車")
# 請求scan_info文件,並打印狀態碼
print(session.get("https://www.zhihu.com/api/v3/account/api/login/qrcode/{0}/scan_info".format(token), headers=HEADERS).status_code)
# 請求編輯頁面
response = session.get("https://www.zhihu.com/people/edit", headers=HEADERS, allow_redirects=False)
if response.status_code == 200:
print("登錄成功")
print(response.text[:10000])
嗯,寫到這兒的時候,宿舍斷網了,因而我打開手機熱點準備測試代碼(之因此要說這個細節,由於我不確實是否是由於使用的手機熱點,才形成了後面的錯誤),結果第一次請求的時候報了以下錯
其實關閉SSL驗證就好,加上參數verify=False
,加了這個參數之後會報InsecureRequestWarning警告,個人處理方式是關閉這個警告。加上以下代碼便可
from requests.packages import urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)
好了,測試代碼吧。效果以下
成功
華麗的分割線—————————————————————————
今天起來測試過了,的確是由於使用手機熱點才形成SLLError。不過我認爲也能夠加上以前的處理措施,避免所以出錯
如今基本功能實現了,但不夠完善
- 好比難道用戶每次使用都要登錄?咱們能夠設置本地cookies,這樣就能夠等cookies失效以後再登錄
- 好比難道每次用戶都要手動去打開二維碼圖片?咱們能夠利用PIL庫來實現圖片自動打開
如下是我程序的總體邏輯設計
如下是我代碼的邏輯設計
由於完整代碼已經上傳GitHub,有詳細註釋,就不在這細說了