爬蟲入門系列(三):用 requests 構建知乎 API


爬蟲入門系列目錄:

  1. 爬蟲入門系列(一):快速理解HTTP協議
  2. 爬蟲入門系列(二):優雅的HTTP庫requests
  3. 爬蟲入門系列(三):用 requests 構建知乎 API

在爬蟲系列文章 優雅的HTTP庫requests 中介紹了 requests 的使用方式,這一次我們用 requests 構建一個知乎 API,功能包括:私信發送、文章點贊、用戶關注等,因為任何涉及用戶操作的功能都需要登錄后才操作,所以在閱讀這篇文章前建議先了解Python模擬知乎登錄 。現在假設你已經知道如何用 requests 模擬知乎登錄了。

思路分析

發送私信的過程就是瀏覽器向服務器發送一個 HTTP 請求,請求報文包括請求 URL、請求頭 Header、還有請求體 Body,只要把這些信息弄清楚,那么就很容易用 requests 來模擬瀏覽器發送私信了。

打開 Chrome 瀏覽器,隨便找一個用戶,點擊發送私信,追蹤一下私信的網絡請求過程。

先看下請求頭信息

zhihu-header.png

請求頭 Header 中有 cookies 登錄信息,此外還有一個 authorization 字段,該字段是用於用戶認證的,同時這個字段也存在 cookies 中(為了防止 cookie 信息泄露,我打了馬賽克), requests 請求時這些信息都必須攜帶上。

再來看看請求的URL和請求體

zhihu-message.png

請求URL是 https://www.zhihu.com/api/v4/messages ,請求方法是 POST,請求體

{"type":"common","content":"你好,我是pythoner","receiver_hash":"1da75b85900e00adb072e91c56fd9149"}

請求體是一個 json 字符串,type 和 content 很好理解,但 receiver_hash 是什么並不知道,需要進一步確定,不過你應該猜得出這是類似於用戶 id 的字段。

那么現在問題來了,如何通過用戶主頁的URL找到用戶的 id 呢?為了完整的模擬私信的整個流程,我特地注冊了一個知乎小號。

如果你手頭沒有多余的手機號,可以用 Google 搜「receive sms online」,網上很多提供免費在線接收短信的手機號碼,我注冊的小號主頁:https://www.zhihu.com/people/xiaoxiaodouzi

先嘗試關注小號,然后在我關注的列表中找到該小號,把鼠標移到小號的頭像處時,發現有一個 HTTP 網絡請求。

zhihu-user.png

請求 url 是 https://www.zhihu.com/api/v4/members/xiaoxiaodouzi ,這個URL的后面部分「xiaoxiaodouzi」對應小號主頁URL的后面部分,這部分我們稱之為 url_token。

接口的返回數據是該用戶的個人公開信息。

{  
   ... "id":"1da75b85900e00adb072e91c56fd9149", "favorite_count":0, "voteup_count":0, "commercial_question_count":0, "url_token":"xiaoxiaodouzi", "type":"people", "avatar_url":"https://pic1.zhimg.com/v2-ca13758626bd7367febde704c66249ec_is.jpg", "is_active":1492224390, "name":"\u6211\u662f\u5c0f\u53f7", "url":"http://www.zhihu.com/api/v4/people/1da75b85900e00adb072e91c56fd9149", "gender":-1 ... } 

我們可以很清楚的看到有個id的字段,跟我們之前猜測的一樣,私信里面的 receiver_hash 字段就是用戶的id。

代碼實現

到此我們把私信功能的思路理清楚了,代碼實現就是水到渠成的事情了。

用戶信息

為了得到私信接口需要的 receiver_hash 字典,我們先要獲取用戶信息,該信息里面含有用於的id值。

@need_login
def user(self, url_token):
    """
    獲取用戶信息,
    :param url_token:
        url_token 是用戶主頁url中后面部分
        例如: https://www.zhihu.com/people/xiaoxiaodouzi
        url_token 是 xiaoxiaodouzi
    :return:dict
    """
    response = self._session.get(URL.profile(url_token))
    return response.json()

發送私信

@need_login
def send_message(self, user_id, content):
    """
    給指定的用戶發私信
    :param user_id: 用戶ID
    :param content: 私信內容
    """
    data = {"type": "common", "content": content, "receiver_hash": user_id}
    response = self._session.post(URL.message(), json=data)
    data = response.json()
    if data.get("error"):
        self.logger.info("私信發送失敗, %s" % data.get("error").get("message"))
    else:
        self.logger.info("發送成功")
    return data

上面兩個方法放在一個叫Zhihu的類里面,我只列出了關鍵代碼,涉及到的 @need_login 是一個用戶認證的裝飾器,表示該方法需要登錄后才能操作。細心的你可能發現,每個請求中我並沒有顯示地指定 Header 字段,那時因為我把它放在 __init__.py 方法中初始化了。

def __init__(self): self._session = requests.session() self._session.verify = False self._session.headers = {"Host": "www.zhihu.com", "Referer": "https://www.zhihu.com/", 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36' ' (KHTML, like Gecko) Chrome/56.0.2924.87', } self._session.cookies = cookiejar.LWPCookieJar(filename=cookie_filename) try: self._session.cookies.load(ignore_discard=True) except: pass 

調用執行

from zhihu import Zhihu if __name__ == '__main__': zhihu = Zhihu() profile = zhihu.user("xiaoxiaodouzi") _id = profile.get("id") zhihu.send_message(_id, "你好,這是來自Python之禪的問候") 

執行完成后,小號成功收到我發送的私信。

zhihu-receiver-message.png

最后,我們可以按照類似的思路把關注用戶,點贊等功能實現了。源碼地址:https://github.com/lzjun567/zhihu-api,歡迎大家 Fork 貢獻代碼,一起完善。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM