python爬蟲—分析Ajax請求對json檔案爬取今日頭條街拍美圖
前言
本次抓取目標是今日頭條的街拍美圖,爬取完成之后,將每組圖片下載到本地并保存到不同檔案夾下,下面通過抓取今日頭條街拍美圖講解一下具體操作步驟,
一、準備
網站:
https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D
環境:anaconda3-spyder
二、分析網頁
一些網頁直接請求得到的HTML代碼其實并沒有我們在網頁中看到的內容,這是因為一些資訊通過Ajax加載了,然后通過JavaScript渲染生成的,這時就需要通過分析網頁的請求來獲取想要爬取的內容,例如我進入街拍這個頁面下,右鍵查看網頁源代碼,再回傳街拍頁面一直向下拉動,街拍頁面會變換出現不同的內容和圖片,再右鍵查看源代碼,發現源代碼和第一次我們查看的源代碼是一樣的,沒有發生變化,并且源代碼很短,如下所示:

所以重點來了,想看資料在哪,我們如何定位呢?
1、Chrome查看的Ajax請求
打開開發者工具,查看所有的網路請求

2、查看URL內的資料

我們再data下面能夠找到title
還能夠找到image_list,包含圖片的鏈接,也就是我們要爬取的圖片url,因此,我們只需要將串列中的url欄位提取出來并下載就ok了,每一組圖都建立一個檔案夾,檔案夾的名稱就為組圖的標題,
3、請求URL和Headers資訊找規律
屬性位置的定位找到了以后,我們還需分析一下URL的變化規律,點擊headers,觀察它的請求URL和Headers資訊,查看第一個headers,紅框里確實包含很多引數
這么多引數不用蒙圈,因為都在下面顯示好了

現在我們查看第二個headers的url引數,發現有一個引數發生了變化,offest由0變成20
我們再觀察第三個headers的url的引數
offest變成了40,所以不難發現,除了offest以外,其他引數都是不變的,只有offest發生變化,并且變化的規律為0、20、40、60…這樣的規律,所以說這個offset值就是偏移量,進而可以推斷出頁面每加載一次,獲取的資料條數為20,因此,我們可以用offset引數來控制資料分頁,通過這個介面批量獲取資料了,然后決議,
三、代碼實作
1、導包
第一個包,主要目的是通過from urllib.parse import urlencode構造完整的URL,Urllib是python內置的HTTP請求庫,urllib.parse url決議模塊,
第四個os模塊主要和檔案路徑相關聯
第五個把字串換成MD5的方法
from urllib.parse import urlencode
import requests
import json
import os
from hashlib import md5
2、首先獲取請求并回傳決議頁面
定義一個函式get_page()來加載單個Ajax請求的結果,由上述分析可知唯一變化的引數就是offset,所以我們將它當作引數傳遞進來,如果訪問成功,狀態碼為200,最后回傳的就是json格式的決議頁面

def get_page(offest):#獲取請求并回傳決議頁面
params = {
'aid': '24',
'app_name': 'web_search',
'offset': offest,
'format': 'json',
'keyword': '街拍',
'autoload': 'true',
'count': '20',
'en_qc': '1',
'cur_tab': '1',
'from': 'search_tab',
'pd': 'synthesis',
'timestamp': '1602563085392',
'_signature': 'LfFmxgAgEBBOl5xAwmvANy3wJ9AAHJ7m7oodN5ACyp.Hg2l3uBmMDqDDDN6rWnqjaV0akHlvj327I-FN9Xrxz9FT7hdlRtmAVGnGPJlX5zzT8tcamaIq51QEsm2ry1w0eu0'
}
url = base_url + urlencode(params)
try:
rq = requests.get(url,headers = headers)
if rq.status_code == 200 :
#print(rq.json())
return rq.json()
except rq.ConnectionError as e:
print('程式錯誤',e.args)
3、決議出data下的title和image_list的url
html為上面函式決議出來的json頁面資訊,我們作為引數傳進這個函式中,需先找到html下的data,再從data下找title和image_list.
def get_images(html):
if html.get('data'): #得到data下的全部內容
for item in html.get('data'): #用item回圈每一條
#這里需要判斷image_list是否為空
title = item.get('title')
if 'image_list' in item and item['image_list'] != []:
images=item['image_list']
for image in images:
yield{
'image': image.get('url'),
'title': title
}#回傳一個字典
4、建檔案夾存圖片
item為data下的所有內容
如果檔案夾不存在,那么就os.mkdir新建一個以title為名的檔案夾,item.get(‘title’)中括號里的title是上面那個函式回傳的
‘image’: image.get(‘url’),
‘title’: title
把它定義成了title
如果我們成功訪問了圖片的鏈接地址,那么就可以圖片命名了,這里用了哈希演算法(我下去還得好好再理解一下),接下來如果檔案夾里面沒東西,就打開檔案夾寫入圖片response.content,
def save_image(item):
#os.path模塊主要用于檔案的屬性獲取,exists是“存在”的意思,
#所以顧名思義,os.path.exists()就是判斷括號里的檔案夾'picture'+str(offset)是否存在的意思,括號內的可以是檔案路徑,
if not os.path.exists(item.get('title')):#判斷當前檔案夾下是否有該檔案
os.mkdir(item.get('title'))#如果不存在就創建該檔案夾
try:
response=requests.get(item['image']) #get函式獲取圖片鏈接地址,requests發送訪問請求,上面那個字典
if response.status_code==200:
file_path='{0}/{1}.{2}'.format(item.get('title'),md5(response.content).hexdigest(),'jpg')
# md5摘要演算法(哈希演算法),通過摘要演算法得到一個長度固定的資料塊,將檔案保存時,通過哈希函式對每個檔案進行檔案名的自動生成,
# md5() 獲取一個md5加密演算法物件
# hexdigest() 獲取加密后的16進制字串
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(response.content)
print('Downloaded image path is: ', file_path)
else:
print('Already Dowloaded',file_path)
except requests.ConnectionError:
print('Failed to Save Image')
5、主函式呼叫
先存如兩頁的圖片
if __name__ == '__main__':
base_url = 'https://www.toutiao.com/api/search/content/?'
headers = {
'referer': 'https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
for offest in range(0,40,20):
html = get_page(offest)
a=get_images(html)
for item in a:
save_image(item)
for i in a:
print(i)
四、結果展示
我把存入的程序依次輸出
查看檔案!


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/179100.html
標籤:其他
