python實現微博個人主頁的資訊爬取

在學習。別問了。發表於2021-01-03

微博個人主頁的資訊爬取

閒話少說,先進入分析過程。
因為相對而言移動端的介面會比較好爬取,所以今天我們爬取移動端微博的頁面,如下:
在這裡插入圖片描述
這裡是前後端分離非同步載入的資料,所以我們去抓包工具下尋找對應的介面地址:
在這裡插入圖片描述
很明顯可以看到crads下對應了多條資料,而其中的mblog下存放著對應微博的相關資料:
在這裡插入圖片描述
不要著急現在就去解析介面資料,先去看看下一頁的載入,怎樣去請求下一條資料:
在這裡插入圖片描述
對比看到多出了一個since_id的資料,發現這個資料的來源是上一條json資料中的:
在這裡插入圖片描述
到這裡我們的分析就結束了,接下來進行程式碼的編寫。

import requests
from urllib.parse import urlencode
import random

# 個人微博內容迴圈爬取,基於強大的requests庫

# 偽裝頭
headers = {
    "Host": "m.weibo.cn",
    "Referer": "https://m.weibo.cn/u/6816603335",
    "user-agent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, "
                  "like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36 Edg/87.0.664.66 ",
    "X-Requested-With": "XMXLHttpRequest"
}
# 介面連結模板
base_url = 'https://m.weibo.cn/api/container/getIndex?'
# ip代理池
proxy_pool = [{'HTTP': '27.206.178.75:9000'}, {'HTTP': '175.42.122.226:9999'}, {'HTTP': '175.42.158.31:9999'},
              {'HTTP': '175.44.109.38:9999'}, {'HTTP': '42.238.91.46:9999'}, {'HTTP': '175.42.158.146:9999'},
              {'HTTP': '123.160.69.171:9999'}, {'HTTP': '115.221.240.115:9999'}, {'HTTP': '183.166.110.5:9999'},
              {'HTTP': '125.121.123.115:8888'}, {'HTTP': '117.64.237.222:1133'}, {'HTTP': '182.87.39.163:9000'},
              {'HTTP': '120.79.184.148:8118'}, {'HTTP': '122.234.24.178:9000'}, {'HTTP': '175.42.158.74:9999'}]
# 預定義字典
weibo = {}

接下來我們進行函式的編寫,封裝兩個函式,用來請求資料 和 解析資料。
請求引數如下:
在這裡插入圖片描述

# 對連結的請求函式
def get_page(since_id=None):
    # 爬取使用者的引數
    params = {
        'uid': '2946150412',
        'luicode': '10000011',
        'lfid': '231093_-_selffollowed',
        'type': 'uid',
        'value': '2946150412',
        'containerid': '1076032946150412',
        'since_id': since_id
    }
    # url拼接
    url = base_url + urlencode(params)
    try:
        # 對拼接字串進行訪問
        response = requests.get(url=url, headers=headers, proxies=random.choice(proxy_pool))
        if response.status_code == 200:
            # 響應成功後,將返回的json資料解析,返回json和其中的since_id
            # since_id是為了迴圈爬取下一條
            json = response.json()
            next_since_id = json.get('data').get('cardlistInfo').get('since_id')
            return json, next_since_id
    except requests.ConnectionError as e:
        # 失敗 控制檯丟擲異常
        print("錯誤:", e.args)

上面的函式會返回一個json物件和since_id的資料,json物件用來解析微博的對應資訊,since_id為我們的下次爬取提供引數

# 解析傳回來的json
def parse_page(json):
    # 部分card屬性下,存放著mblog,即是對應的微博內容
    cards = json.get('data').get('cards')
    for card in cards:
        mblog = card.get('mblog')
        # 迴圈遍歷,獲取對應的每一條資料,有mblog屬性再解析
        if mblog:
            # 釋出微博的來源
            weibo['source'] = mblog['source']
            # 建立時間
            weibo['created_at'] = mblog['created_at']
            # 文字內容
            weibo['raw_text'] = mblog['raw_text']
            # 圖片
            weibo['original_pic'] = mblog.get('original_pic')
            # 圖床的相關處理
            pics = []
            p = mblog.get('pics')
            if p:
                for pic in p:
                    pics.append(pic['url'])
                weibo['pics'] = ' , '.join(pics)
                # 提交
            yield weibo

最後封裝一個函式呼叫上面的兩個方法,並做到迴圈請求和解析的效果。

# 呼叫封裝好的函式並進行持久化儲存
def domain():
    global return_data
    # 迴圈請求資料介面,200次已經很多了,獲取不到對應的since_id時,程式會報錯停止
    for i in range(200):
    # 由於第一頁沒有since_id引數,這裡特殊處理
        if i == 0:
            print("正在爬取第{}頁....".format(i + 1))
            # 第一個介面沒有since_id引數 傳值為空
            return_data = get_page()
            # 下面的語句參照else中的註釋
            results = parse_page(return_data[0])
            for res in results:
                img = res.get('original_pic')
                pics = res.get('pics')
                if img is None:
                    img = "無"
                if pics is None:
                    pics = "無"
                with open('test.txt', 'a', encoding='utf8') as file:
                    file.write('時間:' + res['created_at'] + '\n' + '來源:' + res['source'] + '\n'
                               + '內容:' + res['raw_text'] + '\n' + '附圖連結地址:' + img + '\n'
                               + '圖床:' + pics + '\n' + '\n')
        else:
            print("正在爬取第{}頁....".format(i + 1))
            # 傳入返回的第二個值since_id
            return_data = get_page(return_data[1])
            # 傳入解析的第一個值json物件
            results = parse_page(return_data[0])
            # 遍歷提交的結果
            for res in results:
                # 對照片和圖床進行非空判斷
                img = res.get('original_pic')
                pics = res.get('pics')
                if img is None:
                    img = "無"
                if pics is None:
                    pics = "無"
                # 持久化儲存用文字實現
                with open('test.txt', 'a', encoding='utf8') as file:
                    file.write('時間:' + res['created_at'] + '\n' + '來源:' + res['source'] + '\n'
                               + '內容:' + res['raw_text'] + '\n' + '附圖連結地址:' + img + '\n'
                               + '圖床:' + pics + '\n' + '\n')

執行結果如下:
在這裡插入圖片描述
最後看一下我們的結果檔案:
在這裡插入圖片描述
在這裡插入圖片描述
可以看到最早的2015年的微博也獲取到了,對應的圖片連結也是可以訪問沒有問題的。

相關文章