本文的文字及圖片來源于網路,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯系我們以作處理,
作者:阿里波特
來源:CSDN
Python爬蟲、資料分析、網站開發等案例教程視頻免費在線觀看
https://space.bilibili.com/523606542
一、前言
前文說過我的設計師小伙伴的設計需求,他想做一個披頭士樂隊歷年專輯的瀑布圖,
通過搜索,發現網易云音樂上有比較全的歷年專輯資訊加配圖,圖片質量還可以,雖然有大有小,
我的例子怎么都是爬取圖片?(誰讓你總是跟設計師小伙伴一起玩耍,,,)看來圖片對于設計師來說還是有著很深的情節,那就看他用這些圖片能做出什么樣的作品啦,期待一下,后續會展示一下他的作品,
其實爬取網易云音樂跟之前爬取的網站稍稍有點不同,當然,爬蟲寫的多了就覺得套路都是固定的,見招拆招而已,
二、運行環境
我的運行環境如下:
- 系統版本
Windows10, - Python版本
Python3.5,推薦使用Anaconda 這個科學計算版本,主要是因為它自帶一個包管理工具,可以解決有些包安裝錯誤的問題,去Anaconda官網,選擇Python3.5版本,然后下載安裝, - IDE
我使用的是PyCharm,是專門為Python開發的IDE,
三、實戰
上面提到過,網易云音樂的網頁跟普通的網頁相比主要有兩點不同:
- 網頁是 js 動態加載的
- 使用了iframe框架
所以,首先,網頁請求不能使用requests庫,需要使用Selenium + PhatomJS,其次,使用Selenium + PhatomJS后,還需要針對 iframe 做特定處理,
廢話不多說,看實際操作步驟:
首先打開網頁 http://music.163.com
在右上角的搜索框中輸入“The Beatles”,然后會有一個下拉選項,選擇歌手 The Beatles (紅框中的內容),
然后看到如下頁面,選擇紅框中的“所有專輯”,點擊,
這樣就會看見所有的專輯串列,以及下方的翻頁按鈕,
我們需要的就是所有專輯的圖片、專輯名和專輯出版時間,看到這就可以構想一下爬蟲的爬取邏輯了,定位到該頁面,然后獲取頁碼,然后挨個請求頁面來爬取頁面中的內容,
點擊一下翻頁按鈕看看url 有沒有什么規律,
點擊第二頁后,看到上面的地址欄!!!看到這個地址欄我都懶得翻頁了,,,
limit 引數是限制一個頁面加載專輯的個數
offset 引數是前面過濾多少個專輯,現在是一頁12個專輯,所以第二頁是offset=12,第三頁offset=24,以此類推,,,
一共9頁,一頁12個,也不到120個,So… … 改一下url 就不用翻頁了!!
limit 引數等于120,offset 引數 等于0,就搞定了!輸入下面的url,看看是不是所有的專輯都加載出來了,
http://music.163.com/#/artist/album?id=101988&limit=120&offset=0
下面就開始爬蟲代碼了,
這里我們會用到上一篇博文中寫好的幾個工具方法:
def save_img(self, url, file_name): ##保存圖片 print('開始請求圖片地址,程序會有點長...') img = self.request(url) print('開始保存圖片') f = open(file_name, 'ab') f.write(img.content) print(file_name,'圖片保存成功!') f.close() def request(self, url): #封裝的requests 請求 r = requests.get(url) # 像目標url地址發送get請求,回傳一個response物件,有沒有headers引數都可以, return r def mkdir(self, path): ##這個函式創建檔案夾 path = path.strip() isExists = os.path.exists(path) if not isExists: print('創建名字叫做', path, '的檔案夾') os.makedirs(path) print('創建成功!') return True else: print(path, '檔案夾已經存在了,不再創建') return False def get_files(self, path): #獲取檔案夾中的檔案名稱串列 pic_names = os.listdir(path) return pic_names
OK, 開始我們的爬蟲邏輯部分:
這里值得注意的是,該頁面使用frame 框架,使用Selenium + PhantomJS 后并不會加載iframe 框架中的網頁內容,iframe 框架相當于在頁面中又加載了一個頁面,需要使用Selenium 的 switch_to.frame() 方法加載(官網給的方法是switch_to_frame(),但是IDE提醒使用前面的方法替代該方法),
看下面的網頁結構,iframe的id是“g_iframe”:
加載 iframe 框架中的內容:
driver = webdriver.PhantomJS() driver.get(self.init_url) driver.switch_to.frame("g_iframe") html = driver.page_source
然后找到所有的封面元素:
根據上圖的網頁結構可以看出,所有的專輯資訊都在ul 標簽里面,每一個專輯在一個li 標簽里,li 標簽中包含了圖片url、專輯名字、以及專輯時間,
抓取其中的內容就好了,
all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li') for li in all_li: album_img = li.find('img')['src'] album_name = li.find('p', class_='dec')['title'] album_date = li.find('span', class_='s-fc3').get_text()
這里獲取到的圖片url 依然是有圖片寬高引數的,所以要過濾寬高引數:
http://p4.music.126.net/pLA1GX0KtU-vU4ZA6Cr-OQ==/1401877340532770.jpg?param=120y120
把問號后面的引數過濾掉:
end_pos = album_img.index('?') #找到問號的位置 album_img_url = album_img[:end_pos] #截取問號之前的內容
圖片命名邏輯:專輯時間 + 專輯名,
專輯名可能有一些特殊字符,需要替換掉!
photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg'
再使用上一篇博文例子中的去重邏輯,修改后的爬蟲邏輯部分如下:
def spider(self): print("Start!") driver = webdriver.PhantomJS() driver.get(self.init_url) driver.switch_to.frame("g_iframe") html = driver.page_source self.mkdir(self.folder_path) # 創建檔案夾 print('開始切換檔案夾') os.chdir(self.folder_path) # 切換路徑至上面創建的檔案夾 file_names = self.get_files(self.folder_path) # 獲取檔案夾中的所有檔案名,型別是list all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li') # print(type(all_li)) for li in all_li: album_img = li.find('img')['src'] album_name = li.find('p', class_='dec')['title'] album_date = li.find('span', class_='s-fc3').get_text() end_pos = album_img.index('?') album_img_url = album_img[:end_pos] photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg' print(album_img_url, photo_name) if photo_name in file_names: print('圖片已經存在,不再重新下載') else: self.save_img(album_img_url, photo_name)
其實相對于上篇博文的例子,這個爬蟲的邏輯部分還是挺簡潔的,
最后上一個完整的代碼:也可以從GitHub下載
from selenium import webdriver from bs4 import BeautifulSoup import requests import os class AlbumCover(): def __init__(self): self.init_url = "http://music.163.com/#/artist/album?id=101988&limit=120&offset=0" #請求網址 self.folder_path = "C:\D\TheBeatles" #想要存放的檔案目錄 def save_img(self, url, file_name): ##保存圖片 print('開始請求圖片地址,程序會有點長...') img = self.request(url) print('開始保存圖片') f = open(file_name, 'ab') f.write(img.content) print(file_name, '圖片保存成功!') f.close() def request(self, url): # 封裝的requests 請求 r = requests.get(url) # 像目標url地址發送get請求,回傳一個response物件,有沒有headers引數都可以, return r def mkdir(self, path): ##這個函式創建檔案夾 path = path.strip() isExists = os.path.exists(path) if not isExists: print('創建名字叫做', path, '的檔案夾') os.makedirs(path) print('創建成功!') return True else: print(path, '檔案夾已經存在了,不再創建') return False def get_files(self, path): # 獲取檔案夾中的檔案名稱串列 pic_names = os.listdir(path) return pic_names def spider(self): print("Start!") driver = webdriver.PhantomJS() driver.get(self.init_url) driver.switch_to.frame("g_iframe") html = driver.page_source self.mkdir(self.folder_path) # 創建檔案夾 print('開始切換檔案夾') os.chdir(self.folder_path) # 切換路徑至上面創建的檔案夾 file_names = self.get_files(self.folder_path) # 獲取檔案夾中的所有檔案名,型別是list all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li') # print(type(all_li)) for li in all_li: album_img = li.find('img')['src'] album_name = li.find('p', class_='dec')['title'] album_date = li.find('span', class_='s-fc3').get_text() end_pos = album_img.index('?') album_img_url = album_img[:end_pos] photo_name = album_date + ' - ' + album_name.replace('/', '').replace(':', ',') + '.jpg' print(album_img_url, photo_name) if photo_name in file_names: print('圖片已經存在,不再重新下載') else: self.save_img(album_img_url, photo_name) album_cover = AlbumCover() album_cover.spider()
執行結果:
看看檔案夾里面什么樣:
歷年的專輯封面已經到手啦,還有專輯的名稱和發行日期,
四、后語
這個實戰很好的運用了咱們之前講解的知識:
- 使用Selenium + PhatomJS 抓取動態頁面
- 使用Selenium 的switch_to.frame() 加載 iframe 中的內容
- 使用requests 庫獲取圖片
- 使用BeautifulSoup 庫決議抓取網頁內容,
- 使用os 庫創建檔案夾和獲取檔案夾中的檔案名稱串列
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/251406.html
標籤:Python
上一篇:pandas重塑層次化索引(stack()和unstack()函式決議)
下一篇:1319聯通網路的操作次數

