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·