如何突破常規的反爬限制
今天要記錄的這個爬蟲是我到新工作的第5天接的一個需求,也是我從Java轉Python的第5天寫的一個爬蟲腳本。這個還有腳本有很多可以完善的地方,但也有一些值得參考的地方,下面進行詳細的介紹。
目標網站和爬取素材
目標網站:拍信網 https://www.paixin.com/ (如有冒犯之處,敬請諒解)
爬取素材:各種圖片(在搜索欄中輸入關鍵字,進行查詢得到圖片)
分析過程
怎樣找到目標的url?
首先在搜索欄中輸入關鍵字,進入結果頁面,F12打開谷歌開發者工具,選擇中network面板,刷新頁面;
在選擇xhr(xmlHttpRequest)
圖1
圖2
圖3
分析圖3,根據裏面的請求可知"…search?page=XXX…“請求可以獲取圖片描述和地址以及其他信息,所以該請求就是我們要找的目標url。注意該請求是一個異步請求,返回的數據是json格式的數據。這裏其實有一個坑,看圖2,我從第1頁開始翻頁,翻到第4頁正常來說應該是發送4個請求才對,但是這裏面卻有6個”…search?page=XXX…"請求,且每翻一頁還有“…search_list…”這樣的請求,這是怎麼回事呢?看看這些請求有沒有返回數據,嘗試着在瀏覽器地址欄中發送一下看有什麼結果,綜合分析對比即可發現正確的URL。其實這裏面的一些無用的請求是故意用來迷惑我們的雙眼的,這也是網站的反爬手段之一。
然後我們就可以僞造請求了,剛開始時我在請求頭裏面就寫了一個User-Agent,然後發送請求看一下能否返回數據,結果請求失敗,沒有任何數據返回,然後我又仔細的看了一下Request Headers,裏面的信息的信息很多,我猜測應該是請求頭裏面缺少信息,所以服務器拒絕了請求,既然這樣那就把這些信息放在請求頭裏面,這麼多都需要放嗎?它們分別代表的是什麼意思呢?
headers中的每一項的意義
headers信息中這個referer代表的是referer防盜鏈,是一種常見的反爬手段,指的是該鏈接請求的來源頁面
就這樣我又運行修改後的程序,結果還是沒有返回結果,這到底是怎麼回事?一定是漏掉了什麼,繼續查看檢查了一下headers裏面的信息,發現headers下面有一個Request Playload裏面還有一些參數,那這個Request Playload是什麼呢?
request playload詳解
於是把request playload裏面的數據帶上,發送請求成功返回數據,至此這個爬蟲的難點全部解決。
代碼
分析完了,就直接上代碼吧。
import json
import urllib
import jsonpath
import requests
#拍信創意
def getBlackman(startPage,endPage,path):
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
'Accept': 'application/json, text/plain, */*', 'Accept - Encoding': 'gzip, deflate, br',
'Accept - Language': 'zh - CN, zh;q = 0.9', 'Connection': 'keep-alive', 'Content-Length': '41',
'Content-Type': 'application/json;charset=UTF-8',
'Host': 'api2.paixin.com', 'Origin': 'https://v.paixin.com',
'Referer': 'https://v.paixin.com/media/photo/standard/%E9%BB%91%E4%BA%BA%E5%A4%B4%E5%83%8F/2',
}
requests.packages.urllib3.disable_warnings() #禁用https安全證書的驗證
playloadData = {
'searchQuery':'三明治',
'type': '6',
'searchQuery': '三明治',
'type': '6'
}
for num in range(startPage,(endPage+1)):
images = requests.post('https://api2.paixin.com/medias/b/search?page=' + str((num-1)) + '&size=80',
data=json.dumps(playloadData), headers=header, verify=False,timeout=5)
#data=json.dumps(playloadData) 將dict轉化爲str格式
jsonObjs = json.loads(images.text)
# print(jsonObjs)
images = jsonpath.jsonpath(jsonObjs, '$..image')
i = 1
for image_url in images:
try:
print('*' * 10 + '正在下載第' + str((num - 1) * 80 + i) + '張圖片' + '*' * 10)
res=urllib.request.urlopen(image_url,timeout=5).read()
with open(path + '拍信網第'+str((num-1)*80+i) + '張.jpg','wb') as file:
file.write(res)
file.close()
except Exception as e:
print('第'+str((num-1)*80+i)+'張圖片下載出錯,錯誤信息如下:')
print(' '*10+str(e))
print('')
continue
finally:
i += 1
print('*'*15+'下載完成'+'*'*15)
# def save_image(url,path):
# try:
# res=urllib.request.urlopen(url,timeout=5).read()
if __name__ == '__main__':
getBlackman(1, 16, 'd:/download/拍信/三明治/') # 1頁80張,getBlackman(開始頁,結束頁,圖片存儲路徑)