寫在前面
今天要抓取的網站為 https://500px.me/
,這是一個攝影社區,在一個攝影社區里面本來應該爬取的是圖片信息,可是我發現好像也沒啥有意思的,忽然覺得爬取一下這個網站的攝影師更好玩一些,所以就有了這篇文章的由來。

基於上面的目的,我找了了一個不錯的頁面 https://500px.me/community/search/user
不過細細分析之后,發現這個頁面並不能抓取到盡可能多的用戶,因為下拉一段時間,就不能繼續了,十分糟心,難道我止步於此了么,顯然不可能的,一番的努力之后(大概廢了1分鍾吧),我找到了突破口,任意打開一個用戶的個人中心頁,就是點擊上述鏈接的任意用戶頭像,出現如下操作。
用戶個人中心頁面,竟然有關注列表唉~~,nice啊,這個好趴啊,F12分析一下。
噠噠噠,數據得到了。
URL是 https://500px.me/community/res/relation/4f7fe110d4e0b8a1fae0632b2358c8898/follow?startTime=&page=1&size=10&type=json
參數分別如下,實際測試發現size可以設置為100
https://500px.me/community/res/relation/{用戶ID}/follow?startTime=&page={頁碼}&size={每頁數據}&type=json
那么我們只需要這么做就可以了
- 獲取關注總數
- 關注總數除以100,循環得到所有的關注者(這個地方為什么用關注,不用粉絲,是因為被關注的人更加有價值)
明確我們的目標之后,就可以開始寫代碼了。
擼代碼
基本操作,獲取網絡請求,之后解析頁面,取得關注總數。
用戶的起始,我選擇的id是5769e51a04209a9b9b6a8c1e656ff9566
,你可以隨機選擇一個,只要他有關注名單,就可以。
導入模塊,這篇博客,用到了redis
和mongo
,所以相關的基礎知識,我建議你提前准備一下,否則看起來吃力。
import requests
import threading
from redis import StrictRedis
import pymongo
#########mongo部分#########################
DATABASE_IP = '127.0.0.1'
DATABASE_PORT = 27017
DATABASE_NAME = 'sun'
client = pymongo.MongoClient(DATABASE_IP,DATABASE_PORT)
db = client.sun
db.authenticate("dba", "dba")
collection = db.px500 # 准備插入數據
#########mongo部分#########################
#########redis部分#########################
redis = StrictRedis(host="localhost",port=6379,db=1,decode_responses=True)
#########redis部分#########################
#########全局參數部分#########################
START_URL = "https://500px.me/community/v2/user/indexInfo?queriedUserId={}" # 入口鏈接
COMMENT = "https://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json"
HEADERS = {
"Accept":"application/json",
"User-Agent":"你自己去找找可用的就行",
"X-Requested-With":"XMLHttpRequest"
}
need_crawlids = [] # 待爬取的userid
lock = threading.Lock() # 線程鎖
#########全局參數部分#########################
def get_followee():
try:
res = requests.get(START_URL.format("5769e51a04209a9b9b6a8c1e656ff9566"),
headers=HEADERS,timeout=3)
data = res.json()
if data:
totle = int(data["data"]["userFolloweeCount"]) # 返回關注數
userid = data["data"]["id"] # 返回用戶ID
return {
"userid":userid,
"totle":totle
} # 返回總數據
except Exception as e:
print("數據獲取錯誤")
print(e)
if __name__ == '__main__':
start = get_followee() # 獲取入口
need_crawlids.append(start)
上面代碼中有一個非常重要的邏輯,就是為什么要先匹配種子地址
的【關注數】和【用戶ID】,這兩個值是為了拼接下面的URL
https://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json
經過分析,你已經知道,這個地方第一個參數是用戶id,第二個參數是頁碼page,page需要通過關注總數除以100得到。不會算的,好好在紙上寫寫吧~
我們可以通過一個方法,獲取到了種子用戶的關注列表,以此繼續爬取下去,完善生產者代碼。關鍵代碼都進行了注釋標注。
思路如下:
- 死循環不斷獲取
need_crawlids
變量中的用戶,然后獲取該用戶的關注者列表。 - 爬取到的信息,寫入
redis
方便驗證重復,快速存儲。
class Product(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self._headers = HEADERS
def get_follows(self,userid,totle):
try:
res = requests.get(COMMENT.format(userid,totle),headers=HEADERS,timeout=3)
data = res.json()
if data:
for item in data:
yield {
"userid":item["id"],
"totle":item["userFolloweeCount"]
}
except Exception as e:
print("錯誤信息")
print(e)
self.get_follows(userid,totle) # 出錯之后,重新調用
def run(self):
while 1:
global need_crawlids # 調用全局等待爬取的內容
if lock.acquire():
if len(need_crawlids)==0: # 如果為0,無法進入循環
continue
data = need_crawlids[0] # 取得第一個
del need_crawlids[0] # 使用完刪除
lock.release()
if data["totle"] == 0:
continue
for page in range(1,data["totle"]//100+2):
for i in self.get_follows(data["userid"],page):
if lock.acquire():
need_crawlids.append(i) # 新獲取到的,追加到等待爬取的列表里面
lock.release()
self.save_redis(i) # 存儲到redis里面
def save_redis(self,data):
redis.setnx(data["userid"],data["totle"])
#print(data,"插入成功")
由於500px無反爬蟲,所以運行起來速度也是飛快了,一會就爬取了大量的數據,目測大概40000
多人,由於咱是寫教程的,我停止了爬取。

這些數據不能就在redis里面趴着,我們要用它獲取用戶的所有信息,那么先找到用戶信息接口,其實在上面已經使用了一次
https://500px.me/community/v2/user/indexInfo?queriedUserId={}
后面的queriedUserId
對應的是用戶id,只需要從剛才的數據里面獲取redis的key
就可以了,開始編寫消費者代碼吧,我開啟了5個線程抓取。
class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while 1:
key = redis.randomkey() # 隨機獲取一個key
if key:
# 刪除獲取到的key
redis.delete(key)
self.get_info(key)
def get_info(self,key):
try:
res = requests.get(START_URL.format(key),headers=HEADERS,timeout=3)
data = res.json()
if data['status'] == "200":
collection.insert(data["data"]) # 插入到mongodb中
except Exception as e:
print(e)
return
if __name__ == '__main__':
start = get_followee() # 獲取入口
need_crawlids.append(start)
p = Product()
p.start()
for i in range(1,5):
c = Consumer()
c.start()
代碼沒有特別需要注意的,可以說非常簡單了,關於redis
使用也不多。
redis.randomkey() # 隨機獲取一個key
redis.delete(key) # 刪除key
(⊙o⊙)…經過幾分鍾的等待之后,大量的用戶信息就來到了我的本地。

完整代碼評論留言發送。
寫在后面
emmmmmm...... 天天在CSDN寫博客,明天就爬CSDN博客吧~~~