前言
其實,本篇也是水文,寫這篇的原因是,有同學問要原始碼,既然這與的話,就寫一個吧;
上文連結點這裡,上文主要介紹這個網站反爬的策略,但是沒想到居然有那麼多同學看,受寵若驚;
在寫原始碼的時候,遇到一個坑,就是看到時間戳就預設是當前時間戳,結果自己坑自己了,詳情請看下面介紹吧;
文章很短且很水,一分鐘即可閱讀完;
爬取思路
爬取網站地址點這裡;
多次上滑,介面地址如下:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=1&last_time=0&page_size=40
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=2&last_time=1551141631000&page_size=10
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=3&last_time=1551138631000&page_size=10
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=4&last_time=1551120032000&page_size=10
複製程式碼
首頁這裡,不停上滑,發現就是page
跟last_time
在變化;
一個是頁碼,一個是時間戳;
網站裡面有不同的欄目,每個有什麼不同?
多次嘗試發現,不同欄目,category
會不一樣,簡單分析下,這個值不是按順序固定的,好像沒辦法查?
從程式指令碼,肯定是有地方處理的,比如tabname=熱門
,就返回-1
的值,而且,必然是前端處理的,那一起找出來吧;
方法1:
還是老套路,F12,重新整理整個頁面
;
這裡面就有一個叫get_tabs
的介面,很明顯了;
看吧,一目瞭然了;
方法2:
如果沒有重新整理這個頁面,是不會發現第一種方法的,在一個頁面裡面切換不同的tab,是不會再請求get_tabs
介面的;
這種時候,怎麼辦?沒關係,一個一個看吧;
最終發現,在一個js檔案裡面有個叫tabSelected
的函式,看上去就像有點關係,點選進入看看;
點選後進入的是上面的介面,好像沒太多關係,簡單滑動下?
嘖嘖嘖,就在不遠處,就看到這程式碼了;
這不就是我們想要的關係表嗎?
手動整理下,如下;
欄目名稱 | category值 |
---|---|
熱門 | -1 |
動圖 | 9 |
圖片 | 4 |
美女 | 106 |
丘比龍 | 101 |
搞笑 | 104 |
惡搞 | 105 |
動漫 | 7 |
皮皮蝦 | 107 |
熊本 | 102 |
熊貓人 | 5 |
行吧,再分析下json,獲取image下的large或small即可;
然後就啪啪啪的擼碼,結果發現,不管怎麼爬,永遠都是那40張,用postman看了下,的確發現介面每次返回都一模一樣,如下:
這是第一次,page=1
;
這是第二次,page=2
,但是呢,url地址跟第一次的一模一樣;
一開始以為是Bug,但是多次嘗試跟看回程式碼,都沒發現啥問題,那就重新正視那4個引數吧;
{'category': -1, 'page': '2', 'last_time': '1551398207276', 'page_size': '10'}
複製程式碼
categroy
是欄目分類,page
是頁數,page_size
是請求圖片的資料,唯獨不知道last_time
是什麼;
而jb的程式碼裡面,last_time
用的是時間戳;
重新看介面資訊:
第一次請求:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=1&last_time=0&page_size=40
上滑觸發第二次請求:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=2&last_time=1551402631000&page_size=40
複製程式碼
一開始看到last_time
就是時間戳,就沒細看,但是現在這個時間戳一看,不對啊,現在是11點,為啥顯示9點?那就是說,這個時間戳並非是當前時間戳羅!
換句話說,這裡面肯定是有邏輯吧,行吧,一起看看,還是老套路,看介面js,還是get_data
這個,直接搜尋last_time
,行吧,邏輯都出來了;
看吧,last_time
就是用上一個介面的最後一個圖片的addtime
做標記,怪不得會有問題;
var last = photos[count - 1];
last_time = last.addtime;
複製程式碼
修改下程式碼看看效果吧~
過程輸出:
原始碼:
由於是臨時做的,很不智慧,需要的同學二次封裝下吧,先簡單說說:
# 預設請求一次是40張圖片,如果需要修改,找到下方程式碼直接修改數字即可;
pz_params["page_size"] = "40"
# 分類資訊,預設熱門,需要爬全部欄目,自己寫個陣列,for即可,為啥jb不寫?因為懶;
category = -1
# 這裡是需要爬取的頁數,一次40張;
page_number = 5
# 圖片下載目錄,也可以不用管
dir = "phizhub/remen/"
複製程式碼
好吧,不墨跡,原始碼貼上:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
爬取phizhub表情網站
"""
import time
import requests
import hashlib
import json
import re
import os
# 首頁連結
pz_index_url = "http://www.phizhub.com/"
# 拼接介面地址
pz_url = pz_index_url+"phiz/get_phiz_list/"
# 請求引數的last_time,第一次是0,後面用上一個介面最後一個圖片的addtime做標記
last_time = 0;
# 欄目資訊,熱門是-1,動圖是9,圖片是4,美女是106,丘比龍是101,搞笑是104,惡搞是105,動漫是7,皮皮蝦是107,熊本是102,熊貓人是5
category = -1
# 請輸入需要爬取的頁數
page_number = 5
# 圖片下載目錄
dir = "phizhub/remen/"
# 請求頭,F12直接copy過來
pz_headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Cookie": "SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; gr_user_id=42467006-4ec0-45f7-acdc-91e4060f2262; gr_session_id_a103dce5677f1b74=75095d47-6c68-4ee7-bf81-c2c6be3ece8e; Hm_lvt_fc3add2fc30f38259191ad30ff5813c9=1550714607; gr_session_id_a103dce5677f1b74_75095d47-6c68-4ee7-bf81-c2c6be3ece8e=true; Hm_lpvt_fc3add2fc30f38259191ad30ff5813c9=1550714675",
"Host": "www.phizhub.com",
"Pragma": "no-cache",
"Referer": "http://www.phizhub.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/x-www-form-urlencoded",
"sss": "{sss}",
"timestamp": "{timestamp}"
}
# body
pz_params = {
"category": category,
"page": "{page}",
"last_time": "{last_time}",
"page_size": "{page_size}",
}
# 獲取當前時間的13位時間戳
def get_millistime():
return str(round(time.time() * 1000))
# 獲取sss的值,sss就是phizhub_abc_+當前13位時間戳拼接而成的md5
def get_sss(time):
str = "phizhub_abc_"+ time
return md5Encode(str)
# 獲取md5
def md5Encode(str):
m = hashlib.md5()
m.update(str.encode(encoding='utf-8'))
return m.hexdigest()
# 幹活的地方
def start_job(i):
global last_time;
# 頁碼從1開始算
set_value(i)
response = requests.get(pz_url, headers=pz_headers, params=pz_params, verify=False).json()
# 獲取data裡面的數量,從而獲取對應的圖片連結
count = len(response["data"])
for page in range(count):
print('正在下載圖片:第%s/%s張,' % (page+1, count))
download_Image(response["data"][page]["image"]["large"])
if (page+1 == count):
last_time = response["data"][page]["addtime"]
# 下載圖片
def download_Image(image_link):
if not os.path.exists(dir):
os.makedirs(dir)
filename = get_ImageName(image_link)
with open(dir + filename, 'wb') as f:
# 以二進位制寫入的模式在本地構建新檔案
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.32 Safari/537.36',
'Referer': "http://www.phizhub.com/"}
f.write(requests.get(image_link, headers=header).content)
# 獲取檔名
def get_ImageName(text):
# http://imagecloud.phizhub.com/1551016041657_b58b2935383a11e9b160186590e027b5.gif
pattern = re.compile("http://imagecloud.phizhub.com/")
text = re.sub(pattern, "", text)
return text
# 賦值
def set_value(i):
# 賦值時間戳跟sss
pz_params["page"] = str(i)
time = get_millistime()
pz_headers["timestamp"] = time
pz_headers["sss"] = get_sss(time)
pz_params["last_time"] = last_time
pz_params["page_size"] = "40"
if __name__ == '__main__':
for i in range(1,page_number+1):
print("現在爬第%s頁" % i)
start_job(i)
複製程式碼
小結
再次證明這是水文吧,沒啥好總結的,就是看到時間戳別想當然是當前時間戳;
謝謝大家~