1. 程式人生 > >使用Python抓取網易雲音樂所有歌手資訊

使用Python抓取網易雲音樂所有歌手資訊

思路

1. 構造請求頁面的URL
2. 請求資料

請求資料使用的是requests包,當請求的網址沒有錯誤並且status_code為200時,返回網頁的內容。

注意:這裡並沒改變請求的headers,也沒有使用代理

3. 解析資料

使用lxml包進行html解析,抓取包括歌手id,name,cat,userhome四個資訊

4. 儲存到MongoDB

儲存時將歌手id作為資料表的’_id’,由於歌手id唯一性,可以防止資料庫中的文件重複插入

import requests
from requests.exceptions import RequestException
from
lxml import etree from pymongo import MongoClient from concurrent import futures CATS = { '1001': '華語男歌手', '1002': '華語女歌手', '1003': '華語組合/樂隊', '2001': '歐美男歌手', '2002': '歐美女歌手', '2003': '歐美樂隊/組合', '6001': '日本男歌手', '6002': '日本女歌手'
, '6003': '日本樂隊/組合', '7001': '韓國男歌手', '7002': '韓國女歌手', '7003': '韓國樂隊/組合', '4001': '其他男歌手', '4002': '其他女歌手', '4003': '其他樂隊/組合' } def get_artists(args): ''' 根據不同引數請求不同頁面,並返回歌手資訊 :param args: :return: ''' url = 'http://music.163.com/discover/artist/cat?id={}&initial={}'
.format(args[0],args[1]) result = fetch(url) if result is not None: artists = parse(result,args[0]) return artists def fetch(url): ''' 請求連線,成功時(200)返回頁面內容 :param url: :return: ''' try: resp = requests.get(url) except RequestException: return None if resp.status_code == 200: return resp.text else: return None def parse(page,cat_id): ''' 頁面解析,返回當前頁面所有的歌手資訊 :param page: :param cat_id: :return: ''' html = etree.HTML(page) ul = html.xpath('//ul[@id="m-artist-box"]') lis = ul[0].xpath('li') artists = [] for li in lis: tmp = {} href = li.xpath('a|p/a') tmp['cat'] = CATS[cat_id] tmp['name'] = href[0].text # 使用'_id'儲存歌手的id,能夠保證插入資料的唯一性 tmp['_id'] = href[0].attrib['href'].split('=')[1] # 如果歌手有主頁的話,新增主頁的資訊 if len(href) == 2: tmp['userhome'] = href[1].attrib['href'] else: tmp['userhome'] = None artists.append(tmp) return artists def get_args(hot=False): ''' 根據hot生成請求引數 :param hot: :return: ''' if hot is False: initials = [i for i in range(65, 91)] initials.append(0) else: initials = [-1] return [[cat_no,initial] for cat_no in CATS.keys() for initial in initials] def get_all_artists(hot=False): ''' 1. 初始化請求引數 2. 初始化儲存資訊 3. 獲取並儲存 :param hot: :return: ''' args = get_args(hot) client = MongoClient() db = client['py_netease'] if not hot: artists = db['artists'] else: artists = db['hot_artists'] # 多執行緒下載,用時約24秒 with futures.ThreadPoolExecutor(4) as executor: res = executor.map(get_artists,args) for result in res: try: artists.insert_many(result) except: pass # 單執行緒下載,用時約1分33秒 # for arg in args: # result = get_artists(arg) # try: # artists.insert_many(result) # except: # pass if __name__ == '__main__': get_all_artists()

其他

1. 關於多執行緒

最簡單的方法就是使用concurrent.futures包,其他也可以使用threading包。由於抓取屬於IO密集型,因此使用多執行緒會明顯改善效率。
2. 關於抓取失敗
有可能是IP被禁止訪問,返回503錯誤
3. 最後,發一下效果圖,所有歌手一共有3w+條資料,而熱門歌手有1500條資料

所有歌手

熱門歌手