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

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

思路分析

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

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

先看下請求頭信息python

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

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

請求URL是 www.zhihu.com/api/v4/mess… ,請求方法是 POST,請求體json

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

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

那麼如今問題來了,如何經過用戶主頁的URL找到用戶的 id 呢?爲了完整的模擬私信的整個流程,我特意註冊了一個知乎小號。瀏覽器

若是你手頭沒有多餘的手機號,能夠用 Google 搜「receive sms online」,網上不少提供免費在線接收短信的手機號碼,我註冊的小號主頁:www.zhihu.com/people/xiao… 服務器

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

請求 url 是 www.zhihu.com/api/v4/memb… ,這個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之禪的問候")複製代碼

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

最後,咱們能夠按照相似的思路把關注用戶,點贊等功能實現了。源碼地址:github.com/lzjun567/zh…,歡迎你們 Fork 貢獻代碼,一塊兒完善。

同步發表博客:foofish.net/understand-…
公衆號:Python之禪 (id:VTtalk),分享 Python 等技術乾貨

python之禪
相關文章
相關標籤/搜索