爬取百度圖片
前言:今天我們要爬取的是百度圖片,最終目的是下載用戶輸入的任何類型 圖片
1. 分析網頁,確定是動態還是靜態網頁
首先我們先打開百度圖片,右鍵檢查然後搜索二次元,對網頁進行分析,發現是ajax動態加載的,因爲在往下翻翻閱圖片的時候整個網頁沒有重新加載,所有確定是動態加載的,確定是動態加載的後就打開Network裏面的XHR,這裏面都是異步加載的數據包,之前動態加載圖片的數據包都在裏面,如圖所示
2. 分析ajax加載的數據包,並找到請求url的規律
分析數據包後會發現一次請求就會向服務器獲取30張圖片,而且返回的數據中有三個圖片地址,到時候提取數據的時候任取一個就好
將返回數據中的圖片地址打開後發現正是我們需要下載的圖片
分析請求url的不同之處與特別之處,發現了編碼後的二次元在queryWord和word中,整個url的不同之處就是後面一部分,大概猜想一下,pn肯定就是第多少頁而且一直是30的倍數,rn爲返回來的數據爲多少個,之前分析了一次請求的後返回的數據就是30張圖片
那麼最後面的兩個參數是什麼呢?我們嘗試將其去掉然後去訪問看能否獲取到正確的數據,嘗試後仍能獲取正確的數據,這時我們就只需要改變pn即可以獲取不同的圖片了
我們先嚐試讓pn=0然後去請求數據,觀察pn的初始值是多少,發現當pn爲0時返回的數據中第一張圖片正是網頁中的第一張圖片,所以pn的初始值爲0,且pn是以30的倍數進行增長,一次請求返回30張圖片。
3. 寫代碼
分析完url的規律後我們就可以開始寫代碼了,先寫好整體的思路,然後再慢慢再去細化過程,這裏我來說一下反爬中的一種方法,更改user-agent,下面是我所知的三種隨機選擇用戶代理的方法:
- 自己在程序中定義一個列表,然後再使用random.choice方法去隨機選擇你保存在列表中的請求頭
- 另外創建一個py文件,裏面也定義好列表用random模塊從而隨機獲取用戶代理,然後再從自己正在寫的的程序中去進行導入
- 使用fake_useragent模塊,裏面是已經封裝好了的,直接調用random就可以獲取不同的請求頭,使用方法爲
from fake_useragent import UserAgent
ua = UserAgent()
headers = {'User-Agent':ua.random} # 因爲獲取的只是值,所以需加上User-Agent
寫好整體思路
import requests
from fake_useragent import UserAgent
class BaiduImageSpider(object):
def __init__(self):
self.url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30&gsm=1e&1587812157942='
self.headers = {'User-Agent':ua.random}
# 發送請求獲取json
def get_data(self):
print(self.headers)
# 獲取圖片的url
def get_imageurl(self):
pass
# 向圖片地址發送請求並下載圖片
def save_image(self):
pass
def main(self):
self.get_data()
if __name__ == '__main__':
ua = UserAgent()
spider = BaiduImageSpider()
spider.main()
具體代碼如下:
import requests,json,os,re,time
from fake_useragent import UserAgent
class BaiduImageSpider(object):
def __init__(self):
self.url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30'
self.headers = {'User-Agent': ua.random} # 獲取隨機的用戶代理
# 發送請求獲取json
def get_data(self):
key = input('名字:')
page = int(input('頁數:'))
for i in range(0,page):
url = self.url.format(key,key,i*30)
json_data = requests.get(url,headers = self.headers).text
response = json.loads(json_data,strict=False) # 這裏直接解析會出錯,所以增加一個strict爲False,不嚴格檢查json數據
self.get_imageurl(response)
time.sleep(1) # 發送一次請求後睡眠1秒
# 獲取圖片的url
def get_imageurl(self,response):
datas = response['data']
for data in datas:
try: # 進行異常捕獲
image_url = data['thumbURL']
name = data['fromPageTitleEnc']
self.save_image(image_url, name)
except Exception:
pass # 捕獲到異常不做任何處理
# 向圖片地址發送請求並下載圖片
def save_image(self,image_url,name):
name = re.sub(r'[.。!!/? ?\,【】|*&……)(%#]','',name) # 將一些非法字符替換爲空,防止保存文件時報錯
image = requests.get(image_url,headers = self.headers).content
filename = 'F:/圖片/' # 圖片保存路徑
if not os.path.exists(filename): # 判斷filename是否存在,不存在則創建
os.makedirs(filename)
try: # 因爲替換的name可能補全,所以這裏需要加上異常捕獲
with open(filename+'{}.jpg'.format(name),'wb')as f:
f.write(image)
print('已下載 {}'.format(name))
except Exception: # 捕獲到異常不做任何處理
pass
def main(self):
self.get_data()
if __name__ == '__main__':
ua = UserAgent()
spider = BaiduImageSpider()
spider.main()
最終結果如下
在下載圖片的過程當中可能會有的文件無效,可能是因爲我是隨機用戶代理的原因,如果誰找到了解決的方法,可以在下方留言告訴我,本章的學習到此結束,謝謝大家進行學習,如果有人覺得小編寫的還不錯或者說覺得小編的代碼哪裏還可以改進的,可以在下方進行留言一起交流學習,一起進步