此次爬蟲要實現的是爬取某個微博用戶的關注和粉絲的用戶公開基本信息,包括用戶昵稱、id、性別、所在地和其粉絲數量,然后將爬取下來的數據保存在MongoDB數據庫中,最后再生成幾個圖表來簡單分析一下我們得到的數據。
一、具體步驟:
這里我們選取的爬取站點是https://m.weibo.cn,此站點是微博移動端的站點,我們可以直接查看某個用戶的微博,比如https://m.weibo.cn/profile/5720474518。
然后查看其關注的用戶,打開開發者工具,切換到XHR過濾器,一直下拉列表,就會看到有很多的Ajax請求。這些請求的類型是Get類型,返回結果是Json格式,展開之后就能看到有很多用戶的信息。
這些請求有兩個參數,containerid和page,通過改變page的數值,我們就能得到更多的請求了。獲取其粉絲的用戶信息的步驟是一樣的,除了請求的鏈接不同之外,參數也不同,修改一下就可以了。
由於這些請求返回的結果里只有用戶的名稱和id等信息,並沒有包含用戶的性別等基本資料,所以我們點進某個人的微博,然后查看其基本資料,比如這個,打開開發者工具,可以找到下面這個請求:
由於這個人的id是6857214856,因此我們可以發現當我們得到一個人的id的時候,就可以構造獲取基本資料的鏈接和參數了,相關代碼如下(uid就是用戶的id):
1 uid_str = "230283" + str(uid) 2 url = "https://m.weibo.cn/api/container/getIndex?containerid={}_-_INFO&title=%E5%9F%BA%E6%9C%AC%E8%B5%84%E6%96%99&luicode=10000011&lfid={}&featurecode=10000326".format(uid_str, uid_str) 3 data = { 4 "containerid": "{}_-_INFO".format(uid_str), 5 "title": "基本資料", 6 "luicode": 10000011, 7 "lfid": int(uid_str), 8 "featurecode": 10000326 9 }
然后這個返回的結果也是Json格式,提取起來就很方便,因為很多人的基本資料都不怎么全,所以我提取了用戶昵稱、性別、所在地和其粉絲數量。而且因為一些賬號並非個人賬號,就沒有性別信息,對於這些賬號,我選擇將其性別設置為男性。不過在爬取的時候,我發現一個問題,就是當頁數超過250的時候,返回的結果就已經沒有內容了,也就是說這個方法最多只能爬250頁。對於爬取下來的用戶信息,全都保存在MongoDB數據庫中,然后在爬取結束之后,讀取這些信息並繪制了幾個圖表,分別繪制了男女比例扇形圖、用戶所在地分布圖和用戶的粉絲數量柱狀圖。
二、主要代碼:
由於第一頁返回的結果和其他頁返回的結果格式是不同的,所以要分別進行解析,而且因為部分結果的json格式不同,所以可能報錯,因此采用了try...except...把出錯原因打印出來。
爬取第一頁並解析的代碼如下:
1 def get_and_parse1(url): 2 res = requests.get(url) 3 cards = res.json()['data']['cards'] 4 info_list = [] 5 try: 6 for i in cards: 7 if "title" not in i: 8 for j in i['card_group'][1]['users']: 9 user_name = j['screen_name'] # 用戶名 10 user_id = j['id'] # 用戶id 11 fans_count = j['followers_count'] # 粉絲數量 12 sex, add = get_user_info(user_id) 13 info = { 14 "用戶名": user_name, 15 "性別": sex, 16 "所在地": add, 17 "粉絲數": fans_count, 18 } 19 info_list.append(info) 20 else: 21 for j in i['card_group']: 22 user_name = j['user']['screen_name'] # 用戶名 23 user_id = j['user']['id'] # 用戶id 24 fans_count = j['user']['followers_count'] # 粉絲數量 25 sex, add = get_user_info(user_id) 26 info = { 27 "用戶名": user_name, 28 "性別": sex, 29 "所在地": add, 30 "粉絲數": fans_count, 31 } 32 info_list.append(info) 33 if "followers" in url: 34 print("第1頁關注信息爬取完畢...") 35 else: 36 print("第1頁粉絲信息爬取完畢...") 37 save_info(info_list) 38 except Exception as e: 39 print(e)
爬取其他頁並解析的代碼如下:
1 def get_and_parse2(url, data): 2 res = requests.get(url, headers=get_random_ua(), data=data) 3 sleep(3) 4 info_list = [] 5 try: 6 if 'cards' in res.json()['data']: 7 card_group = res.json()['data']['cards'][0]['card_group'] 8 else: 9 card_group = res.json()['data']['cardlistInfo']['cards'][0]['card_group'] 10 for card in card_group: 11 user_name = card['user']['screen_name'] # 用戶名 12 user_id = card['user']['id'] # 用戶id 13 fans_count = card['user']['followers_count'] # 粉絲數量 14 sex, add = get_user_info(user_id) 15 info = { 16 "用戶名": user_name, 17 "性別": sex, 18 "所在地": add, 19 "粉絲數": fans_count, 20 } 21 info_list.append(info) 22 if "page" in data: 23 print("第{}頁關注信息爬取完畢...".format(data['page'])) 24 else: 25 print("第{}頁粉絲信息爬取完畢...".format(data['since_id'])) 26 save_info(info_list) 27 except Exception as e: 28 print(e)
三、運行結果:
在運行的時候可能會出現各種各樣的錯誤,有的時候返回結果為空,有的時候解析出錯,不過還是能成功爬取大部分數據的,這里就放一下最后生成的三張圖片吧。
完整代碼已上傳到GitHub!





