python 爬取 instagram 用戶的關注列表
- 2019 年 12 月 15 日
- 筆記
0 前言
這是很久之前我的房東找我幫忙爬 instagram 上面某個用戶的關注列表,一開始我想着減低難度好給他使用,於是嘗試了 webscraper,后羿採集器去爬取,結果吭哧吭哧花了兩個多小時都沒搞定。
於是我就直接寫代碼來爬取了,用 python 寫個代碼,半小時就好了?
1 分析過程
先訪問用戶主頁,然後 F12 打開控制台,接着點擊 Network,然後在下面選中 XHR。

用戶主頁
在頁面中點擊 正在關注,會出現下圖中圈出的網絡請求

XHR(XML Http Request)
點擊第一個加載出來的請求,然後點擊 Preview 查看一下加載的數據是否一致,是否一一對應。
username、followed_by_viewer、profile_pic_url 那些如果一一對應,那就是這個請求了,沒找錯。

數據
那麼點擊 Headers ,然後找到 Request Headers。
這裡非常重要,Request Headers也就是請求頭裏面攜帶了重要的信息 cookie,要是沒有 cooike 的話,那就爬取不了了。
代碼中需要把請求頭裏面的信息加上才能爬取內容。

Request Headers
拉到最下面就是 Query String Parameters,請求的參數,query_hash 照着來就好,一般不會變。
variable 裏面有個 id ,每個用戶的 id 是不同的,所以要爬另一個用戶關注的用戶列表的話,需要進行替換。

Query String Parameters 雙擊這個請求,瀏覽器會新開一個標籤頁來訪問這個鏈接。

鏈接 在谷歌擴展程序【JSONVIEW】的加持下,看到是內容是下圖這樣的;如果不加持的話,所有的文字都是擠在一起的。
簡單分析一下, count 應該就是該用戶關注了多少個人, has_next_page 就是有沒有下一頁,end_cursor 是查看下一頁的關鍵,用來構造請求。
每一個 node 裏面就是一個用戶的信息。

數據
id 是用戶的 id;username 是用戶名,是 instagram.com/eltaautomotive 後面的那一個用來標識用戶的字符串;full_name 應該類似微信昵稱。

用戶界面
2 代碼思路
使用 requests 去構造請求,把請求頭和參數加上,提取獲取到的內容,has_next_page用來判斷有沒有下一頁,end_cursor 用來構造下一個請求,id,username,full_name 是需要的內容,保存到 csv 裏面。
3 代碼 + 解釋
首先是導入需要用到的包,這裡只有 requests 是需要 pip install requests 進行安裝的,別的都是 python 自帶的包。
requests 是用來請求網站,獲得數據的;json 是把獲取到的 json 數據轉化為 python 對象;csv 是用來把數據保存到 csv 裏面;time 是用來 sleep 的,兩個請求之間加上一點時間間隔。
import csv import json import requests from time import sleep
先構造一個請求頭,把需要的東西進行替換
# cookie 是需要替換的,referer 最好是替換一下 headers = { 'sec-ch-ua': 'Google Chrome 77', 'sec-fetch-mode': 'cors', 'dnt': '1', 'x-ig-www-claim': 'hmac.AR1P1exDcpFRvpFAYKNm_Wnajygy1QK5l3HC7cN5943dNlY-', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', 'sec-fetch-dest': 'empty', 'x-requested-with': 'XMLHttpRequest', 'cookie': r'這裡是cookie,需要自行替換', 'x-csrftoken': '1vBpb3wLDDDbC63ckwu06IzIy351nB12', 'x-ig-app-id': '936619743392459', 'accept-encoding': 'gzip, deflate, br', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36', 'accept': '*/*', 'referer': 'https://www.instagram.com/linda_ledo_carlights/following/', 'authority': 'www.instagram.com', 'sec-fetch-site': 'same-origin', }
然後是 end_cursor ,這個是用來構造下一頁的請求鏈接,一開始為空;has_next 是有沒有下一頁,用來循環獲取列表。
end_cursor = '' has_next = True
下面這個就是一個循環,只有 has_next 不為 True 的時候才退出循環。
params 是請求所帶的參數,每一頁的參數都是不同的,通過不同的 end_cursor 來訪問不同的頁數。
然後用 requests 去獲取到數據,獲取到的數據用 json.loads() 把數據從 json 對象轉為 python 對象。
接着從轉化之後的數據中獲取 has_next、end_cursor 並且賦值。
edges 是用戶列表,獲取之後遍歷一下就能把每一個用戶的id, username, full_name 的信息。
打開一個 csv 把爬取到的信息保存進去,關閉 csv,接着程序 sleep 23.3 秒之後判斷是否進入 while 循環。(sleep的數值可以修改,但是建議不要低於 5)
while has_next: # id是需要替換的,每一個用戶的 id 不一樣 params = ( ('query_hash', 'd04b0a864b4b54837c0d870b0e77e076'), ('variables', '{"id":"5848320586","include_reel":true,"fetch_mutual":false,"first":12,"after":"' + end_cursor + '"}'), ) response = requests.get('https://www.instagram.com/graphql/query/', headers=headers, params=params).text res = json.loads(response) has_next = res['data']['user']['edge_follow']['page_info']['has_next_page'] print(has_next) end_cursor = res['data']['user']['edge_follow']['page_info']['end_cursor'] edges = res['data']['user']['edge_follow']['edges'] out = open("ig.csv", "a+", newline="", encoding="utf-8-sig") csv_writer = csv.writer(out, dialect="excel") for i in edges: row = [i['node']['id'], i['node']['username'], i['node']['full_name']] csv_writer.writerow(row) out.close() sleep(23.3) print("=============搞定收工==============")
把代碼從頭到尾複製下來,替換一下需要替換的部分,運行之後就能在代碼的同級目錄下看到一個 ig.csv 的文件,打開之後就能看到數據了。


