Python爬蟲教程:爬取知乎網
- 2019 年 10 月 4 日
- 筆記
前言
Python現在非常火,語法簡單而且功能強大,很多同學都想學Python!所以小的給各位看官們準備了高價值Python學習影片教程及相關電子版書籍,歡迎前來領取!
知乎已經成為了爬蟲的訓練場,本文利用Python中的requests庫,模擬登陸知乎,獲取cookie,保存到本地,然後這個cookie作為登陸的憑證,登陸知乎的主頁面,爬取知乎主頁面上的問題和對應問題回答的摘要。
關於知乎驗證碼登陸的問題,用到了Python上一個重要的圖片處理庫PIL,如果不行,就把圖片存到本地,手動輸入。
爬取知乎的關鍵的部分:模擬登陸
通過對知乎登陸是的抓包,可以發現登陸知乎,需要post三個參數,一個是帳號,一個是密碼,一個是xrsf。 這個xrsf隱藏在表單裡面,每次登陸的時候,應該是伺服器隨機產生一個字元串。所有,要模擬登陸的時候,必須要拿到xrsf。
用chrome (或者火狐 httpfox 抓包分析)的結果:

所以,必須要拿到xsrf的數值,注意這是一個動態變化的參數,每次都不一樣。

注意findall和find_all函數的區別。
拿到xsrf,下面就可以模擬登陸了。 使用requests庫的session對象,建立一個會話的好處是,可以把同一個用戶的不同請求聯繫起來,直到會話結束都會自動處理cookies。

注意:cookies 是當前目錄的一個文件,這個文件保存了知乎的cookie,如果是第一個登陸,那麼當然是沒有這個文件的,不能通過cookie文件來登陸。必須要輸入密碼。
def login(secret, account): # 通過輸入的用戶名判斷是否是手機號 if re.match(r"^1d{10}$", account): print("手機號登錄 n") post_url = 'https://www.zhihu.com/login/phone_num' postdata = { '_xsrf': get_xsrf(), 'password': secret, 'remember_me': 'true', 'phone_num': account, } else: if "@" in account: print("郵箱登錄 n") else: print("你的帳號輸入有問題,請重新登錄") return 0 post_url = 'https://www.zhihu.com/login/email' postdata = { '_xsrf': get_xsrf(), 'password': secret, 'remember_me': 'true', 'email': account, } try: # 不需要驗證碼直接登錄成功 login_page = session.post(post_url, data=postdata, headers=headers) login_code = login_page.text print(login_page.status_code) print(login_code) except: # 需要輸入驗證碼後才能登錄成功 postdata["captcha"] = get_captcha() login_page = session.post(post_url, data=postdata, headers=headers) login_code = eval(login_page.text) print(login_code['msg']) session.cookies.save() try: input = raw_input except: pass
這是登陸的函數,通過login函數來登陸,post 自己的帳號,密碼和xrsf 到知乎登陸認證的頁面上去,然後得到cookie,將cookie保存到當前目錄下的文件裡面。下次登陸的時候,直接讀取這個cookie文件。
#LWP-Cookies-2.0 Set-Cookie3: cap_id=""YWJkNTkxYzhiMGYwNDU2OGI4NDUxN2FlNzBmY2NlMTY=|1487052577|4aacd7a27b11a852e637262bb251d79c6cf4c8dc""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:37Z"; version=0 Set-Cookie3: l_cap_id=""OGFmYTk3ZDA3YmJmNDQ4YThiNjFlZjU3NzQ5NjZjMTA=|1487052577|0f66a8f8d485bc85e500a121587780c7c8766faf""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:37Z"; version=0 Set-Cookie3: login=""NmYxMmU0NWJmN2JlNDY2NGFhYzZiYWIxMzE5ZTZiMzU=|1487052597|a57652ef6e0bbbc9c4df0a8a0a59b559d4e20456""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:57Z"; version=0 Set-Cookie3: q_c1="ee29042649aa4f87969ed193acb6cb83|1487052577000|1487052577000"; path="/"; domain=".zhihu.com"; path_spec; expires="2020-02-14 06:09:37Z"; version=0 Set-Cookie3: z_c0=""QUFCQTFCOGdBQUFYQUFBQVlRSlZUVFVzeWxoZzlNbTYtNkt0Qk1NV0JLUHZBV0N6NlNNQmZ3PT0=|1487052597|dcf272463c56dd6578d89e3ba543d46b44a22f68""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:57Z"; httponly=None; version=0
這是cookie文件的內容
以下是源碼:
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests try: import cookielib except: import http.cookiejar as cookielib import re import time import os.path try: from PIL import Image except: pass from bs4 import BeautifulSoup # 構造 Request headers agent = 'Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0' headers = { "Host": "www.zhihu.com", "Referer": "https://www.zhihu.com/", 'User-Agent': agent } # 使用登錄cookie資訊 session = requests.session() session.cookies = cookielib.LWPCookieJar(filename='cookies') try: session.cookies.load(ignore_discard=True) except: print("Cookie 未能載入") def get_xsrf(): '''_xsrf 是一個動態變化的參數''' index_url = 'https://www.zhihu.com' # 獲取登錄時需要用到的_xsrf index_page = session.get(index_url, headers=headers) html = index_page.text pattern = r'name="_xsrf" value="(.*?)"' # 這裡的_xsrf 返回的是一個list _xsrf = re.findall(pattern, html) return _xsrf[0] # 獲取驗證碼 def get_captcha(): t = str(int(time.time() * 1000)) captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login" r = session.get(captcha_url, headers=headers) with open('captcha.jpg', 'wb') as f: f.write(r.content) f.close() # 用pillow 的 Image 顯示驗證碼 # 如果沒有安裝 pillow 到源程式碼所在的目錄去找到驗證碼然後手動輸入 try: im = Image.open('captcha.jpg') im.show() im.close() except: print(u'請到 %s 目錄找到captcha.jpg 手動輸入' % os.path.abspath('captcha.jpg')) captcha = input("please input the captchan>") return captcha def isLogin(): # 通過查看用戶個人資訊來判斷是否已經登錄 url = "https://www.zhihu.com/settings/profile" login_code = session.get(url, headers=headers, allow_redirects=False).status_code if login_code == 200: return True else: return False def login(secret, account): # 通過輸入的用戶名判斷是否是手機號 if re.match(r"^1d{10}$", account): print("手機號登錄 n") post_url = 'https://www.zhihu.com/login/phone_num' postdata = { '_xsrf': get_xsrf(), 'password': secret, 'remember_me': 'true', 'phone_num': account, } else: if "@" in account: print("郵箱登錄 n") else: print("你的帳號輸入有問題,請重新登錄") return 0 post_url = 'https://www.zhihu.com/login/email' postdata = { '_xsrf': get_xsrf(), 'password': secret, 'remember_me': 'true', 'email': account, } try: # 不需要驗證碼直接登錄成功 login_page = session.post(post_url, data=postdata, headers=headers) login_code = login_page.text print(login_page.status_code) print(login_code) except: # 需要輸入驗證碼後才能登錄成功 postdata["captcha"] = get_captcha() login_page = session.post(post_url, data=postdata, headers=headers) login_code = eval(login_page.text) print(login_code['msg']) session.cookies.save() try: input = raw_input except: pass ## 將main的問題列表輸出在shell上面 def getPageQuestion(url2): mainpage = session.get(url2, headers=headers) soup=BeautifulSoup(mainpage.text,'html.parser') tags=soup.find_all("a",class_="question_link") #print tags for tag in tags: print tag.string # 將main頁面上面的問題的回答的摘要輸出在shell上面 def getPageAnswerAbstract(url2): mainpage=session.get(url2,headers=headers) soup=BeautifulSoup(mainpage.text,'html.parser') tags=soup.find_all('div',class_='zh-summary summary clearfix') for tag in tags: # print tag print tag.get_text() print '詳細內容的鏈接 :',tag.find('a').get('href') def getPageALL(url2): #mainpage=session.get(url2,headers=headers) #soup=BeautifulSoup(mainpage.text,'html.parser') #tags=soup.find_all('div',class_='feed-item-inner') #print "def getpageall " mainpage=session.get(url2,headers=headers) soup=BeautifulSoup(mainpage.text,'html.parser') tags=soup.find_all('div',class_='feed-content') for tag in tags: #print tag print tag.find('a',class_='question_link').get_text() # 這裡有一點問題 bs 還是用的不是太熟練 #print tag.find('a',class_='zh-summary summary clearfix').get_text() #print tag.find('div',class_='zh-summary summary clearfix').get_text() if __name__ == '__main__': if isLogin(): print('您已經登錄') url2='https://www.zhihu.com' # getPageQuestion(url2) #getPageAnswerAbstract(url2) getPageALL(url2) else: account = input('請輸入你的用戶名n> ') secret = input("請輸入你的密碼n> ") login(secret, account)
運行結果:

ps:想學習python的朋友這裡推薦一下我建的python零基礎系統學習交流扣扣qun:322795889,群里有免費的影片教程,開發工具、電子書籍分享。專業的老師答疑!學習python web、python爬蟲、數據分析、人工智慧等技術有不懂的可以加入一起交流學習,一起進步!
好啦!文章就給看官們分享到這兒
最後,如果覺得有幫助,記得關注、轉發、收藏喲
·END·