python爬蟲實戰---今日頭條的圖片抓取
本文是主要在今日頭條裡面的以“街拍路人”為搜尋條件去提取網頁的圖片和標題,並把標題當做資料夾的名稱,建立該資料夾,把圖片儲存到相應的資料夾下。
匯入庫
from urllib.parse import urlencode---把字典裡面的資料拼接成如下字串格式:
urlencode()的方法接受引數形式為:[(key1,value),(key2,value2),.....]或者可以是字典的形式:{‘key’:‘value1’,‘key2’:‘value2’,....}返回格式為key1=value1&key2=value2的字串。
from urllib.error import HTTPError---進行異常處理
from multiprocessing.pool import Pool---執行緒池
import requests---網頁請求
import os---檔案操作
import re---正則表示式的使用
爬取的資料(網頁)
這是其中的一部分將要提取的內容,其中的圖片和標題是我們提取的重點
網頁分析
從分析來看,該資料是通過非同步載入AJAX,開啟瀏覽器餓netword點選XHR再重新整理網頁,就可以看到格式為json的資料,點選其中一個再點選preview就可以發現在data列表裡面有我們想要的資料,裡面的title就是我們要抓取的資料標題,image_list列表的資料就是可以找到我們想要的圖片的連結。每次我們只要請求這個url就可以了,且這個url只有offset在變化,每次只需要傳入offset的值即可。
獲取資料轉換為json格式
def get_page(offset): # 設定請求頭 headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'} # 設定請求引數 data={ 'offset':offset, 'format':'json', 'keyword':'街拍路人', 'autoload':'true', 'count':'20', 'cur_tab':'1', 'from':'search_tab' } # 把data字典裡面的資料轉換為字串的格式,再去拼接字串 url='https://www.toutiao.com/search_content/?'+urlencode(data) try: response=requests.get(url,headers=headers) # 判斷請求的狀態(200表示請求成功) if response.status_code == 200: # 將結果轉換成json格式再返回 return response.json() except HTTPError: return None
資料解析
def get_images(offset):
json=get_page(offset)
if json !=None:
if json.get('data'):
for item in json.get('data'):
title=item.get('title')
images=item.get('image_list')
if images:
for img in images:
yield{
'image':img.get('url'),
'title':title
}
儲存圖片
首先根據提取到的標題去建立該資料夾,在拼接請求的url,然後對url進行處理,把url如//p3.pstatp.com/list/pgc-image/15293938122252e5eb4198a中的15293938122252e5eb4198a作為圖片的名稱。
def save_images(item):
# 判斷該資料夾是否存在,不存在則建立
if not os.path.exists(item.get('title')):
os.mkdir(item.get('title'))
# 獲取圖片連結,再去下載圖片
try:
headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
# 字串拼接
reponse=requests.get('http:'+item.get('image'),headers=headers)
if reponse.status_code == 200:
# 正則表示式匹配url後面的數字如//p3.pstatp.com/list/pgc-image/15293938122252e5eb4198a中的15293938122252e5eb4198a
image_name=re.match('//p[0-9].*?(list/|list/pgc-image/)(.*)',item.get('image')).group(2)
if 'pgc-image/' in image_name:
# 字串切片
image_name=image_name[10:]
elif re.search('[0-9]*/(.*)',image_name):
image_name=re.search('[0-9]*/(.*)',image_name).group(1)
# 圖片的路徑+名稱
file_path='{0}/{1}.{2}'.format(item.get('title'),image_name,'jpg')
# 判斷是否存在該圖片了
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(reponse.content)
else:
print('該圖片已經下載了!')
except HTTPError:
print('儲存圖片失敗')
執行緒池
if __name__=='__main__':
# 建立執行緒池
pool=Pool()
offset=([x*20 for x in range(start,end)])
# 第一個引數是函式,第二個引數是一個迭代器,把迭代器的數字作為引數傳進去
pool.map(main,offset)
# 關閉執行緒池
pool.close()
# 主執行緒阻塞等待子執行緒的退出
pool.join()