使用Python抓取網易雲音樂所有歌手資訊
阿新 • • 發佈:2019-02-02
思路
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條資料