Python爬取qq音樂的過程實例

零下一度
發布: 2017-07-18 15:28:28
原創
4001 人瀏覽過

一、前言


  qq music上的音樂還是不少的,有些時候想下載好聽的音樂,但有每次在網頁下載都是煩人的登入什麼的。於是,來了qqmusic的爬蟲。至少我覺得for循環爬蟲,最核心的應該就是找到待爬元素所在url吧。下面開始找(講的不對不要笑我)

<br>

#二、Python爬取QQ音樂單曲


之前看的慕課網的一個影片, 很好地講解了一般編寫爬蟲的步驟,我們也按這個來。

          爬蟲步驟

1.確定目標

#1.確定目標

首先我們要先明確目標,這次爬取的是QQ音樂歌手劉德華的單曲。

(百度百科)->分析目標(策略:url格式(範圍)、資料格式、網頁編碼)->編寫程式碼->執行爬蟲

#2.分析目標

 歌曲連結:

從左邊的截圖可以知道單曲採用分頁的方式排列歌曲訊息,每頁顯示30條,總共30頁。點擊頁碼或最右邊的">"會跳到下一頁,瀏覽器會向伺服器發送ajax非同步請求,從連結可以看到begin和num參數,分別代表起始歌曲下標(截圖是第2頁,起始下標是30)和一頁回傳30條,伺服器回應回傳json格式的歌​​曲訊息(MusicJsonCallbacksinger_track({"code":0,"data":{"list":[{"Flisten_count1":. .....]})),如果只是單獨想獲取歌曲信息,可以直接拼接鏈接請求和解析返回的json格式的數據。這裡不採用直接解析資料格式的方法,我採用的是Python Selenium方式,每獲取和解析完一頁的單曲信息,點擊">" 跳到下一頁繼續解析,直至解析並記錄所有的單曲資訊。最後請求每個單曲的鏈接,獲取詳細的單曲信息。

 右邊的截圖是網頁的原始碼,所有歌曲資訊都在類別名稱為mod_songlist的div浮層裡面,類別名稱為songlist_list的無序列表ul下,每個子元素li展示一個單曲,類別名為songlist__album下的a標籤,包含單曲的鏈接,名稱和時長等。

 

<br>#3.寫程式碼

1 )下載網頁內容,這裡使用Python 的Urllib標準庫,自己封裝了一個download方法:

def download(url, user_agent='wswp', num_retries=2):
    if url is None:
        return None
    print('Downloading:', url)
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
    request = urllib.request.Request(url, headers=headers)  # 设置用户代理wswp(Web Scraping with Python)
    try:
        html = urllib.request.urlopen(request).read().decode('utf-8')
    except urllib.error.URLError as e:
        print('Downloading Error:', e.reason)
        html = None
        if num_retries > 0:
            if hasattr(e, 'code') and 500 <= e.code < 600:
                # retry when return code is 5xx HTTP erros
                return download(url, num_retries-1)  # 请求失败,默认重试2次,
    return html
登入後複製

2)解析網頁內容,這裡使用第三方插件BeautifulSoup,具體可以參考BeautifulSoup API 。

def music_scrapter(html, page_num=0):
    try:
        soup = BeautifulSoup(html, 'html.parser')
        mod_songlist_div = soup.find_all('div', class_='mod_songlist')
        songlist_ul = mod_songlist_div[1].find('ul', class_='songlist__list')
        '''开始解析li歌曲信息'''
        lis = songlist_ul.find_all('li')
        for li in lis:
            a = li.find('div', class_='songlist__album').find('a')
            music_url = a['href']  # 单曲链接
            urls.add_new_url(music_url)  # 保存单曲链接
            # print('music_url:{0} '.format(music_url))
        print('total music link num:%s' % len(urls.new_urls))
        next_page(page_num+1)
    except TimeoutException as err:
        print('解析网页出错:', err.args)
        return next_page(page_num + 1)
    return None
登入後複製
def get_music():
     try:
        while urls.has_new_url():
            # print('urls count:%s' % len(urls.new_urls))
            '''跳转到歌曲链接,获取歌曲详情'''
            new_music_url = urls.get_new_url()
            print('url leave count:%s' % str( len(urls.new_urls) - 1))
            html_data_info = download(new_music_url)
            # 下载网页失败,直接进入下一循环,避免程序中断
            if html_data_info is None:
                continue
            soup_data_info = BeautifulSoup(html_data_info, 'html.parser')
            if soup_data_info.find('div', class_='none_txt') is not None:
                print(new_music_url, '   对不起,由于版权原因,暂无法查看该专辑!')
                continue
            mod_songlist_div = soup_data_info.find('div', class_='mod_songlist')
            songlist_ul = mod_songlist_div.find('ul', class_='songlist__list')
            lis = songlist_ul.find_all('li')
            del lis[0]  # 删除第一个li
            # print('len(lis):$s' % len(lis))
            for li in lis:
                a_songname_txt = li.find('div', class_='songlist__songname').find('span', class_='songlist__songname_txt').find('a')
                if 'https' not in a_songname_txt['href']:  #如果单曲链接不包含协议头,加上
                    song_url = 'https:' + a_songname_txt['href']
                song_name = a_songname_txt['title']
                singer_name = li.find('div', class_='songlist__artist').find('a').get_text()
                song_time =li.find('div', class_='songlist__time').get_text()
                music_info = {}
                music_info['song_name'] = song_name
                music_info['song_url'] = song_url
                music_info['singer_name'] = singer_name
                music_info['song_time'] = song_time
                collect_data(music_info)
     except Exception as err:  # 如果解析异常,跳过
         print('Downloading or parse music information error continue:', err.args)
登入後複製

4.執行爬蟲

#

<span style="font-size: 16px;">爬虫跑起来了,一页一页地去爬取专辑的链接,并保存到集合中,最后通过get_music()方法获取单曲的名称,链接,歌手名称和时长并保存到Excel文件中。</span><br><span style="font-size: 14px;"><img src="https://img.php.cn/upload/article/000/000/001/a1138f33f00f8d95b52fbfe06e562d24-4.png" alt=""    style="max-width:90%"  style="max-width:90%"><strong><img src="https://img.php.cn/upload/article/000/000/001/9282b5f7a1dc4a90cee186c16d036272-5.png" alt=""></strong></span>
登入後複製
<br>
登入後複製

三、Python爬取QQ音樂單曲總結

1.單曲採用的是分頁方式,切換下一頁是透過非同步ajax請求從伺服器取得json格式的資料並渲染到頁面,瀏覽器網址列連結是不變的,不能透過拼接連結來請求。一開始想過都透過Python Urllib函式庫來模擬ajax請求,後來想還是用Selenium。 Selenium能夠很好地模擬瀏覽器真實的操作,頁面元素定位也很方便,模擬點擊下一頁,不斷地切換單曲分頁,再透過BeautifulSoup解析網頁源碼,獲取單曲資訊。  

2.url連結管理器,採用集合資料結構來保存單曲鏈接,為什麼要使用集合?因為多首單曲可能來自同一專輯(專輯網址一樣),這樣可以減少請求次數。

class UrlManager(object):<br>    def __init__(self):<br>        self.new_urls = set()  # 使用集合数据结构,过滤重复元素<br>        self.old_urls = set()  # 使用集合数据结构,过滤重复元素
登入後複製
    def add_new_url(self, url):<br>        if url is None:<br>            return<br>        if url not in self.new_urls and url not in self.old_urls:<br>            self.new_urls.add(url)<br><br>    def add_new_urls(self, urls):<br>        if urls is None or len(urls) == 0:<br>            return<br>        for url in urls:<br>            self.add_new_url(url)<br><br>    def has_new_url(self):<br>        return len(self.new_urls) != 0<br><br>    def get_new_url(self):<br>        new_url = self.new_urls.pop()<br>        self.old_urls.add(new_url)<br>        return new_url<br><br>
登入後複製

3.透過Python第三方外掛程式openpyxl讀寫Excel十分方便,把單曲資訊透過Excel檔案可以很好地保存起來。

###
def write_to_excel(self, content):<br>    try:<br>        for row in content:<br>            self.workSheet.append([row['song_name'], row['song_url'], row['singer_name'], row['song_time']])<br>        self.workBook.save(self.excelName)  # 保存单曲信息到Excel文件<br>    except Exception as arr:<br>        print('write to excel error', arr.args)<br><br>
登入後複製
######四、後語################最後還是要慶祝下,畢竟成功把QQ音樂的單曲訊息爬取下來了。這次能夠成功爬取單曲,Selenium功不可沒,這次只是用到了selenium一些簡單的功能,後續會更加深入學習Selenium,不僅在爬蟲方面還有UI自動化。 ######

後續還需要優化的點:

1.下載的連結比較多,一個一個下載起來比較慢,後面打算用多執行緒並發下載。

2.下載速度過快,為了避免伺服器停用IP,後面還要對於同一網域存取過於頻繁的問題,有個等待機制,每個請求之間有個等待間隔。

3. 解析網頁是一個重要的過程,可以採用正規表示式,BeautifulSoup和lxml,目前採用的是BeautifulSoup庫, 在效率方面,BeautifulSoup沒lxml效率高,後面會嘗試採用lxml。

 

以上是Python爬取qq音樂的過程實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!