Python多线程爬取QQ音乐的专辑信息

来源:互联网 发布:梦幻古龙服务端源码 编辑:程序博客网 时间:2024/06/10 11:50

1 需求:

   获取专辑信息:

   专辑名字,歌手,流派,语种,发行时间,发行公司,类型,介绍

   以及专辑中的歌曲,歌手和时长

   全部保存为json格式

2 分析页面

   

   专辑链接所在的url为上图右方的链接:去掉多余参数则如下图所示:

   

   page从0开始。

   观察专辑的链接,

   

   

   红框中的内容恰好是一图中的album_mid所对应的值。

   打开专辑链接,要获取的内容如下:

   


   通过多次试着爬取,发现专辑中的信息并不统一,大概分为5类:

   第一类:就是上图完整的类型

   第二类:即完整类型中缺少了一个,要么是类型,要么是发行公司。需要进行判断。

   第三类:

   如图:没有歌手名字,并且是四个小字段。需要写判断。

   第四类:

   和上图是同种类型,但是是3个小字段。依旧需要写判断。

   第五类:

           

    

     

   这两种情况属于请求失败,当请求失败时,会直接返回null。此时创建空字典,让所有键对应的值为空。

   下面是代码,写的不好,请多指教。

   1 qq_music.py

   

# -*- coding: utf-8 -*-"""获取专辑信息专辑名字,歌手,流派,语种,发行时间,发行公司,类型,简介专辑中的歌曲,歌手和时长数据全部存储为json格式(qqMusic0.json)"""import requestsimport jsonfrom bs4 import BeautifulSoupimport headers_fileimport loggingimport timeimport sysreload(sys)sys.setdefaultencoding('utf-8')logging.basicConfig(level=logging.DEBUG,                    format='%(asctime)s %(levelname)s %(message)s',                    datefmt='%a, %d %b %Y %H:%M:%S',                    filename='qqM.log',                    filemode='w')class QQMusic:    def __init__(self):        pass    # 获取所有专辑的链接    def getAlbumLinks(self):        album_links = []        for page_num in range(1000):  # page从0开始            base_url = 'https://c.y.qq.com/v8/fcg-bin/album_library?cmd=get_album_info&page='+str(page_num)+'&pagesize=20&sort=1'            logging.info(base_url)            time.sleep(10)            page = requests.get(base_url, headers=headers_file.request_headers())            html = page.content            # 替换掉开头结尾,用于json和字典的转换            html2 = html.replace('MusicJsonCallback(', '')            html3 = html2.replace('})', '}')            html_dict = json.loads(html3)            album_list = html_dict['data']['albumlist']            # 获取关键字album_mid的内容,拼接成专辑的链接            for album in album_list:                link_id = album['album_mid']                # print link_id                album_link = 'https://y.qq.com/n/yqq/album/'+str(link_id)+'.html'                album_links.append(album_link)        return album_links    # 获取专辑的详细信息    def getAlbumInfo(self, url):        logging.info(url)        album_dict = {}  # 创建字典储存所有信息        try:            time.sleep(20)            info_page = requests.get(url, headers=headers_file.request_headers())            info_html = info_page.text            # print info_html            soup = BeautifulSoup(info_html, 'html.parser')            album_name = soup.find_all('h1', class_='data__name_txt')[0].get_text(strip=True)  # 专辑名称            album_dict['album_name'] = album_name            # 有的也没有歌手,没有歌手信息的,以下5个小信息对应的key不同。            # 多出来的演奏,译名舍掉,key值存为空            singer = soup.find_all('a', class_='js_singer data__singer_txt')  # 歌手            if len(singer) == 0:                info_all = soup.find_all('li', class_='data_info__item')  # 演奏,发行时间,发行公司,译名,类型。                album_dict['singer'] = "null"                album_dict['music_genre'] = "null"                album_dict['language'] = "null"                # 有的也没有类型                if len(info_all) == 4:                    pub_time = info_all[1].get_text(strip=True)  # 发行时间                    pub_company = info_all[2].get_text(strip=True)  # 发行公司                    album_dict['pub_time'] = pub_time                    album_dict['pub_company'] = pub_company                    # album_type = info_all[3].get_text(strip=True)  # 类型                    album_dict['album_type'] = 'null'                # 这个条件下有的info_all长度只有3, 只有发行公司、发行时间、类型                elif len(info_all) == 3:                    pub_time = info_all[0].get_text(strip=True)  # 发行时间                    pub_company = info_all[1].get_text(strip=True)  # 发行公司                    album_dict['pub_time'] = pub_time                    album_dict['pub_company'] = pub_company                    album_type = info_all[2].get_text(strip=True)  # 类型                    album_dict['album_type'] = album_type                else:                    pub_time = info_all[1].get_text(strip=True)  # 发行时间                    pub_company = info_all[2].get_text(strip=True)  # 发行公司                    album_dict['pub_time'] = pub_time                    album_dict['pub_company'] = pub_company                    album_type = info_all[4].get_text(strip=True)  # 类型                    album_dict['album_type'] = album_type            else:                singer2 = singer[0].get_text(strip=True)                album_dict['singer'] = singer2                info_all = soup.find_all('li', class_='data_info__item')  # 流派,语种,发行时间,发行公司,类型等信息在一起                                # 有的没有发行公司,长度为4,完整的5个都有,长度为5                # 突然发现,有的也没有类型。。。。                if len(info_all) == 4:                    music_genre = info_all[0].get_text(strip=True)   # 流派                    language = info_all[1].get_text(strip=True)  # 语种                    pub_time = info_all[2].get_text(strip=True)  # 发行时间                    unknown = info_all[3].get_text(strip=True)                    if '发行公司' in unknown:                        pub_company = unknown                        album_dict['pub_company'] = pub_company  # 发行公司                        album_dict['album_type'] = "无"                    if '类型' in unknown:                        album_type = unknown                        album_dict['album_type'] = album_type  # 专辑类型                        album_dict['pub_company'] = "无"                    album_dict['music_genre'] = music_genre                    album_dict['language'] = language                    album_dict['pub_time'] = pub_time                else:                    music_genre = info_all[0].get_text(strip=True)  # 流派                    language = info_all[1].get_text(strip=True)  # 语种                    pub_time = info_all[2].get_text(strip=True)  # 发行时间                    pub_company = info_all[3].get_text(strip=True)  # 发行公司                    album_type = info_all[4].get_text(strip=True)  # 专辑类型                    album_dict['music_genre'] = music_genre                    album_dict['language'] = language                    album_dict['pub_time'] = pub_time                    album_dict['pub_company'] = pub_company                    album_dict['album_type'] = album_type            album_intro = soup.find_all('div', class_='about__cont')[0].get_text(strip=True)  # 专辑简介            album_dict['album_intro'] = album_intro            # 有的专辑简介为空            if len(album_intro) == 0:                album_intro = "null"                album_dict['album_intro'] = album_intro            # 专辑内的所有歌曲信息            song_list = []            songs = soup.find_all('span', class_='songlist__songname_txt')  # 歌名            for i in songs:                song = i.get_text(strip=True)                song_list.append(song)            artist_list = []            artists = soup.find_all('div', class_='songlist__artist')  # 演唱者            for i in artists:                 artist = i.get_text(strip=True)                 artist_list.append(artist)            time_list = []            song_time = soup.find_all('div', class_='songlist__time')  # 时长            for i in song_time:                time_minute = i.get_text(strip=True)                time_list.append(time_minute)            album_info = zip(song_list, artist_list, time_list)            album_info2 = []            for item in album_info:                songs_list = dict()                songs_list['song'] = item[0]                songs_list['who_sing'] = item[1]                songs_list['time'] = item[2]                album_info2.append(songs_list)            album_dict['album_info2'] = album_info2            # print album_dict, url            return album_dict        except Exception as e:            logging.info(e)            # 有的页面会请求失败,一个是版权无法查看,一个是找不到该页面,此时返回空字典,value全部为null            album_dict['album_name'] = "null"            album_dict['singer'] = "null"            album_dict['music_genre'] = "null"            album_dict['language'] = "null"            album_dict['pub_time'] = "null"            album_dict['pub_company'] = "null"            album_dict['album_type'] = "null"            album_dict['album_intro'] = "null"            album_dict['album_info2'] = "null"            return album_dict

   2 music_thread.py

   

# -*- coding: utf-8 -*-import threadingimport Queuefrom qq_music import *q = Queue.Queue()lock = threading.Lock()qm = QQMusic()class MusicThread(threading.Thread):    def __init__(self, queue):        threading.Thread.__init__(self)        self.queue = queue    def run(self):        while True:            if self.queue.qsize() > 0:                url = self.queue.get()                f = open('qqMusic0.json', 'a+')                try:                    content = qm.getAlbumInfo(url)                    lock.acquire()                    f.write(json.dumps(content)+'\n')                    lock.release()                    f.close()                except Exception as e:                    logging.error(e)                    continue            else:                logging.warn('none')                breakdef main():    for url in qm.getAlbumLinks():        # print url        q.put(url)    ts = []    for i in range(20):        t = MusicThread(q)        t.setDaemon(True)        t.start()        ts.append(t)    for t in ts:        t.join()if __name__ == '__main__':    main()

   3 headers_file.py 

   用来轮换user_agent


昂,有一个错误:


   这是在服务器上跑数据,日志中写入的错误。应该是请求过快了,设置睡眠也无济于事,只好在本机上自己跑数据了。

   有没有知道这该怎么处理的小伙伴呐,多谢指教。啦啦啦啦~~~



0 0
原创粉丝点击