赞
踩
本次分享是对QQ音乐网页中部分歌手前十首热门歌曲的基本信息(歌手名,个人简介,歌曲名,所在专辑和发行时间)进行一个爬取收集并录入Excel文件中。
首先让我们先了解一下爬虫的基本流程。
python中提供了requests、urllib等很多库来帮助我们获取页面信息。本篇文章使用的是requests库
我们运用第三方库获取的网页信息是原始的,没有经过处理的数据,我们需要通过处理筛选提取自己所需要的数据,在这里我们利用的是bs4(BeautiSoup)库来提取信息的。
我们通过筛选获取到的大量数据,我们可以按照用多种形式来保存。如:可以保存为txt文本、Excel文件或者存储到数据库中。甚至可以直接存储到服务器中。大家可以根据自己后期对该数据的使用或者查看方式来选择保存信息的方式。
爬虫的工作复杂起来是一个庞大繁琐的程序,这时我们可以通过一些自动化工具帮助我们的爬虫运行。
整体是一个xls文件,里面包含多张表格分别对应每个歌手的信息。接下来让我们一起来分析一下这个结果的实现过程。
如何找到我们需要的数据的第一步也是最重要的一步便是分析网页,首先让我们先打开QQ音乐歌手界面的网页,并按【Fn+F12】调出开发者工具。
以许嵩为例分析网页代码,选中他可以到跳转代码处
展开该处代码我们会发现这是一个层级标签代码,
在这段代码中我们可以分析出几个重点内容:
让我们对许嵩进行一个深入的了解,点击他的名字进入他的主页后点击全部进入以下页面,然后再次打开开发者工具
根据自己对数据的要求,除去他的姓名,我们还需要知道他的个人简介,歌曲名,专辑名,歌曲时长和发行时间,在本页面我们可以找到前四个要求的位置和代码
在此时,我们点击这首歌跳转的网页会有一个有趣的现象
根据以上分析,我们可以联想到,如果利用爬虫程序在QQ音乐游走获取数据,所需要的url几乎可以分为两个部分
那么可以用python中的字符串拼接,对网页进行深度或者广度的爬取
综上,我们可以总结出这只“爬虫”的轨迹如下图所示:
一个歌手是这样走的路线,那么多个歌手也是这么走,大家可以多分析几位歌手来体会一下有趣的爬虫历程。
- import requests
- from bs4 import BeautifulSoup
- import xlwt
Python requests 是一个常用的 HTTP 请求库,可以方便地向网站发送 HTTP 请求,并获取响应结果。导入后就可以发送 HTTP 请求,使用 requests 提供的方法向指定 URL 发送 HTTP 请求。
我们简称bs4库,他可以从 HTML 或 XML 文档中快速地提取指定的数据。帮助我们筛选提取数据,Beautiful Soup 语法简单,使用方便,并且容易理解
在获取提取信息数据之后,保存数据我选择了xlwt库,将数据写入excel文件。
目的是为了让我们的表格更加美观
-
- def create_table_style(n):
- if(n==1):
- style = xlwt.XFStyle() # 初始化样式
- font = xlwt.Font() # 为样式创建字体
- font.name = 'Times New Roman'
- font.height = 20 * 13 # 字体大小,11为字号,20为衡量单位
- font.bold = True # 黑体
- font.underline = False # 下划线
- font.italic = True # 斜体字
-
- al = xlwt.Alignment()
- al.horz = 0x02 # 设置水平居中
- al.vert = 0x01 # 设置垂直居中
-
- borders = xlwt.Borders() # Create Borders
- borders.left = xlwt.Borders.THIN # DASHED虚线,NO_LINE没有,THIN实线
- borders.right = xlwt.Borders.THIN # borders.right=1 表示实线
- borders.top = xlwt.Borders.THIN
- borders.bottom = xlwt.Borders.THIN
- borders.left_colour = 0x40
- borders.right_colour = 0x40
- borders.top_colour = 0x40
- borders.bottom_colour = 0x40
-
- pattern = xlwt.Pattern()
- pattern.pattern = xlwt.Pattern.SOLID_PATTERN
- pattern.pattern_fore_colour = 29
-
- style.font = font # 设定样式
- style.borders = borders
- style.pattern = pattern
- style.alignment = al
- style.alignment.wrap = 1
- return style
- if (n == 2):
- style = xlwt.XFStyle() # 初始化样式
- font = xlwt.Font() # 为样式创建字体
- font.name = 'Times New Roman'
- font.height = 20 * 13 # 字体大小,11为字号,20为衡量单位
- font.bold = True # 黑体
- font.underline = False # 下划线
- font.italic = False # 斜体字
-
- al = xlwt.Alignment()
- al.horz = 0x02 # 设置水平居中
- al.vert = 0x01 # 设置垂直居中
-
- borders = xlwt.Borders() # Create Borders
- borders.left = xlwt.Borders.THIN # DASHED虚线,NO_LINE没有,THIN实线
- borders.right = xlwt.Borders.THIN # borders.right=1 表示实线
- borders.top = xlwt.Borders.THIN
- borders.bottom = xlwt.Borders.THIN
- borders.left_colour = 0x40
- borders.right_colour = 0x40
- borders.top_colour = 0x40
- borders.bottom_colour = 0x40
-
- style.font = font # 设定样式
- style.borders = borders
- style.alignment = al
- style.alignment.wrap = 1
- return style
'运行
一切为了美观
- def set_column_width(sum,worksheet):
- for i in range(sum):
- worksheet.col(i).width = 320 * 30
-
-
- def set_row_height(sum,worksheet):
- for i in range(sum):
- tall_style = xlwt.easyxf('font:height 480;') # 36pt
- worksheet.row(i).set_style(tall_style)
'运行
对于文件中的每一个表,他的第一行为歌手的名字,所以写了一个函数来实现
- def table_head(data, data_table, style):
- data_table.write_merge(0, 0, 0, 3 ,data, style) #输入时合并单元格
- # (0,0,0,3)表示合并的是第一行的1~3列
'运行
- def singer_infto_entry_table(data, data_table, style1,style2):
- data_table.write_merge(1,1,0,3, "简介", style1)
- data_table.write_merge(2,5,0,3, data,style2)
- # 输入时合并单元格
- # (1,1,0,3)表示合并的是第二行的1~3列
- # (2,5,0,3)表示将3~6行的1~3列都给合并了
'运行
实现的是这一部分
- def table_header(bs, data,data_table, style):
- for i in range(len(data)):
- data_table.write(6,i,data[i],style)
'运行
以上是对Excel文件表格样式等做了规范美观的函数
- def get_html_data(url):
- """
- 获取网页数据,生成bs对象
- :param url: 所要爬取的网页的网址
- :return: 返回一个bs对象,用于后续的数据获取
- """
- r1 = requests.get(url, 'lxml')
- r1.encoding = 'utf-8'
- bs_1 = BeautifulSoup(r1.text, 'lxml')
- return bs_1
'运行
- def get_singer_brief_info(bs):
- """
- 获取获取歌手的姓名和个人简介
- :param bs: 提供提取数据的手段方法的bs对象
- :return: 返回歌手的姓名和个人简介
- """
- list = bs.select("div[class='data__cont']") #用bs中的select方法找到class属性值等于 data__cont的数据集
- # print(list)
- singer_name = ''
- singer_info = ''
- for li in list:
- singer_name = li.div.h1.string # 遍历该数据集去找到所需要的信息
- singer_info = li.find("div", class_="data__desc_txt").string
- return singer_name, singer_info
'运行
- def get_the_songs_header(bs):
- """
-
- :param bs: 提供提取数据的手段方法的bs对象
- :return: 返回我们需要获得的歌曲的信息头
- """
- list = []
- song_list = bs.find_all(attrs={'class': 'songlist__header'})
- for h in song_list:
- for li in h:
- content = li.string
- list.append(content)
- list.append("发行时间")
- return list
'运行
- def song_entry_table(bs,datatable,style):
- """
- 将每个歌手的歌曲信息录入表格
- :param bs: 提供提取数据的手段方法的bs对象
- :param datatable: 表格对象
- :param style: 表格的样式
- :return:
- """
- song_list = bs.find_all(attrs={'class': 'songlist__item'}) # 根据对网页的分析,找到attrs={'class': 'songlist__item'}的代码部分就可以找到自己想要的数据
- song_name = []
- song_group = []
- song_time = []
- # 先将信息加入列表,再遍历录入表格对象中
- for h in song_list:
- song_name.append(h.find(attrs={'class': 'songlist__songname_txt'}).find('a')['title']) # 对于多级标签的代码筛选查找可以多次调用find方法
- try:
- # 通过分析网站会发现不是所有歌都有专辑,所以对获取专辑名字的代码进行异常处理,一旦触发异常就录入没有专辑的字样
- song_group.append(h.find(attrs={'class': 'songlist__album'}).find('a').text)
- except AttributeError:
- song_group.append("无专辑")
- song_time.append(h.find(attrs={'class': 'songlist__time'}).text)
- for i in range(len(song_name)):
- datatable.write(i+7,0,song_name[i],style)
- datatable.write(i+7,1,song_group[i],style)
- datatable.write(i+7,2,song_time[i],style)
'运行
- def get_release_time(bs):
- """
- 获取歌曲发行时间
- :param bs: 提供提取数据的手段方法的bs对象
- :return:返回该歌手歌曲发行时间的列表
- """
- # 实现思想,歌曲详情网页网址由两部分组成,我们可以用一个列表将该歌手的每首歌的href属性值都找到,再分别和first_url = 'https://y.qq.com'进行拼接获得我们即将请求访问的下一个网页网址
- song_list = bs.find_all(attrs={'class': 'songlist__item'})
- first_url = 'https://y.qq.com'
- second_url = []
- for h in song_list:
- second_url.append(h.find(attrs={'class': 'songlist__songname_txt'}).find('a')['href'])
- time_list = []
- song_url = first_url + second_url[0]
- r = requests.get(song_url, 'lxml')
- r.encoding = 'utf-8'
- bs2 = BeautifulSoup(r.text, 'lxml')
- # 循环分别访问每首歌的详情网页获取发行时间数据加入time_list
- for i in range(len(second_url)):
- song_url = first_url + second_url[i]
- r = requests.get(song_url, 'lxml')
- r.encoding = 'utf-8'
- bs2 = BeautifulSoup(r.text, 'lxml')
- i = 4
- try:# 通过分析网页我们会发现,每首歌的详细介绍可能不同,就会导致我们的发行时间的位置不同,采用异常处理,一旦超过索引,就往前继续遍历,直到找不到发行时间,降低录入数据的错误率
- time_list.append(bs2.find_all(attrs={'class': 'data_info__item_song'})[i].text[5:])
- except IndexError:
- while i >=0:
- i-=1
- try:
- time_list.append(bs2.find_all(attrs={'class': 'data_info__item_song'})[i].text[5:])
- except IndexError:
- continue
- else:
- break
- return time_list
'运行
- def set_release_time(data,data_table,style):
- """
- 将发行时间录入表格
- :param data: 通过get_release_time函数获得的发行时间列表
- :param data_table:
- :param style:
- :return:
- """
- for i in range(len(data)):
- data_table.write(i+7,3,data[i],style)
'运行
- def get_singers_links():
- """
- 在歌手总页面获取所有歌手的主页面
- :return: 返回一个歌手:url的字典集
- """
- url = 'https://y.qq.com/n/ryqq/singer_list'
- bs = get_html_data(url)
- href_list = []
- name_list = []
- first_link_list = bs.find_all(attrs={'class':'singer_list_txt__link js_singer'})
- for li in first_link_list:
- name_list.append(li["title"])
- href_list.append(li["href"])
- singer_url_dict = dict(zip(name_list,href_list))
- return singer_url_dict
'运行
- def create_singer_sheet(data):
- """
- 生成xls文件
- :param data: 是通过get_singers_links函数获得的所有歌手页面href值的数据集,是一个字典
- :return:
- """
- first_url = 'https://y.qq.com/'
- last_url = '/song'
- for person in data: # 页面中获取到几个歌手href值就会循环几次,文件中就会有几个表
- url = first_url+data[person]+last_url #拼接出完整的网址
- # 调用函数
- bs = get_html_data(url)
- singer_info = get_singer_brief_info(bs)
- print(singer_info)
- header_list = get_the_songs_header(bs)
- worksheet = workbook.add_sheet(singer_info[0])
- set_column_width(4,worksheet)
- set_row_height(18,worksheet)
- style1 = create_table_style(1)
- style2 = create_table_style(2)
- table_head(singer_info[0], worksheet, style1)
- singer_infto_entry_table(singer_info[1], worksheet, style1,style2)
- table_header(bs,header_list, worksheet, style1)
- song_entry_table(bs,worksheet,style2)
- time_list = get_release_time(bs)
- set_release_time(time_list,worksheet,style2)
'运行
- if __name__ == '__main__':
- singer_url_dict = get_singers_links()
- create_singer_sheet(singer_url_dict)
- workbook.save("歌手热门前十歌曲基本信息.xls")
虽然这只是一个简单的实例但是我们可以总结到关于爬虫的一些重要思想
以上是我本次python爬虫简单实例的拙见和分享,欢迎大家参考和指正(*^▽^*)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。