分析并构造请求网址
爬取酷狗音乐TOP500 的‘音乐名’,‘歌手’,‘歌名’,‘播放时间’,‘网址’这几个数据网址如下:https://www.kugou.com/yy/rank/home/1-8888.html?from=rank
,浏览器打开网址分析,第一页只显示了22首歌曲:
我们可以看到,其中有一个 1-8888 这个参数,打开上述网址后我们只能看到前 22 首歌,想继续查看后面的歌曲就得翻页,就像“淘宝”那样查看下一页商品需要翻页,这里也是一样的道理,把 1-8888 改成 2-8888 ,就会看到下一页的 22 首歌,如下:
翻到第 200首音乐那一页,可以看到页码如下有 10 页,那么可以如下构造URL地址:
"""将所有URL构造成一个列表集合"""
URLs=["https://www.kugou.com/yy/rank/home/{}-8888.html?from=rank".format(str(i)) for i in range(1,10)]
构造请求
try:
res=requests.get(url)
res.encoding=res.apparent_encoding # 转换编码,不然中文会显示乱码,也可以r.encoding = 'utf-8'
if res.status_code== 200:
html=res.text
return html
except:
print("请求失败")
使用 requests
库的 get
方法,去访问网页,res
其中里面有很多结果:状态响应码,网页源码,二进制等。调用请求结果 res
中的 status_code
查看请求状态码response.status_code == 200
返回响应结果的 html
,代表返回网页 html
源码
解析数据
soup=BeautifulSoup(html,"lxml")
"""
html 表示被解析的html格式的内容
lxml 表示解析用的解析器
"""
提取数据
分析网页源代码:
可以看到需要的一些信息如‘音乐名’,‘歌手’,‘歌名’,‘播放时间’,‘网址’等分别在如图标注的地方,每个歌曲信息所在的标签结构如下:所有歌曲信息都在<div>
标签下,每首歌曲都在各自的<ul>
标签,然后歌曲自身的‘音乐名’,‘歌手’,‘歌名’等信息都分别由一个<li>
标签包裹。
把每首歌曲的‘音乐名’,‘歌手’,‘歌名’,‘播放时间’,‘网址’的值都取出来,并且把每组数据都各自装在一个列表中。
(1)使用select
方法定位
"""(1)使用`select`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
try:
nums=soup.select('.pc_temp_num' ) #定位排名
titles=soup.select('.pc_temp_songname') #定位歌手-歌名
times=soup.select('.pc_temp_time' ) #定位播放时间
except:
print("位置定位失败")
select
方法主要采用的是CSS
定位,如果不熟悉的话,可以参考http://www.w3school.com.cn/cssref/css_selectors.asp
了解。常用的select
搜索:
.intro | 选择 |
#firstname | 选择 |
div p | 选择 |
div>p | 选择父元素为 |
这里因为排名class="pc_temp_num"
唯一,所以直接定位到该标签。歌手-可以通过class="pc_temp_songname"
定位到<a>
标签,然后在获取属性值。
(2)使用find
方法定位
"""(2)使用`find`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
try:
div=soup.find("div",class_="pc_temp_songlist") #先定位 div
lis=div.find("ul").children #获取 ul标签下面的 子标签->li
for li in lis: #通过循环获取每个 li 标签
if isinstance(li,bs4.element.Tag): #确保 li 对象的类型是bs4.element.Tag,也就是标签对象。只有标签对象才能使用find方法
nums=li.select(".pc_temp_num")
titles=[li.a.attrs]
times=li.find(class_="pc_temp_time")
except:
print("位置定位失败")
(3)使用find_all
方法定位
"""(3)使用`find_all`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
try:
nums=soup.find_all(class_="pc_temp_num")
titles=soup.find_all(class_="pc_temp_songname")
times=soup.find_all(class_="pc_temp_time")
except:
print("位置定位失败")
获得数据
"""打印信息 """
for num,title,time in zip(nums,titles,times):
data={"排名":num.get_text().replace('\n','').replace('\t','').replace('\r',''),
"歌手-歌名":title.string,
"播放时间":time.string.replace('\n','').replace('\t','').replace('\r',''),
"网址":title.attrs["href"]}
print(data)
用了zip
函数,意思是把对应的排名,歌名歌手,播放时间打包,可以这样理解 zip
函数的结果是一个列表 [(排名,歌手歌名,播放时间),(排名,歌手歌名,播放时间)]
每一次循环的 num,title,time,href
对应一次元组中的元素
get_text()
我们提取到的是这个数据所在的标签信息,并不是实际数据,所以需要使用 get_text()
获得实际数据
.replace('\n','').replace('\t','').replace('\r','')
去掉实际数据中多余的字符串;
最后把数据打包成字典打印。
最终代码
from bs4 import BeautifulSoup
import requests
import bs4
def get_html(url):
try:
res=requests.get(url)
res.encoding=res.apparent_encoding # 转换编码,不然中文会显示乱码,也可以r.encoding = 'utf-8'
if res.status_code== 200:
html=res.text
return html
except:
print("请求失败")
def get_infos(html):
soup=BeautifulSoup(html,"lxml")
"""
html 表示被解析的html格式的内容
lxml 表示解析用的解析器
"""
"""(1)使用`select`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
try:
nums=soup.select('.pc_temp_num' ) #定位排名
titles=soup.select('.pc_temp_songname') #定位歌手-歌名
times=soup.select('.pc_temp_time' ) #定位播放时间
except:
print("位置定位失败")
# """(2)使用`find`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
# try:
# div=soup.find("div",class_="pc_temp_songlist") #先定位 div
# lis=div.find("ul").children #获取 ul标签下面的 子标签->li
# for li in lis: #通过循环获取每个 li 标签
# if isinstance(li,bs4.element.Tag): #确保 li 对象的类型是bs4.element.Tag,也就是标签对象。只有标签对象才能使用find方法
# nums=li.select(".pc_temp_num")
# titles=[li.a.attrs]
# times=li.find(class_="pc_temp_time")
# for num,title,time in zip(nums,titles,times):
# data={"排名":num.get_text().replace('\n','').replace('\t','').replace('\r',''),
# "歌手-歌名":title["title"],
# "播放时间":time.string.replace('\n','').replace('\t','').replace('\r',''),
# "网址":title["href"]}
# print(data)
# except:
# print("位置定位失败")
# """(3)使用`find_all`方法定位,提取数据 ,返回结果为列表,下面使用循环依次取出数据"""
# try:
# nums=soup.find_all(class_="pc_temp_num")
# titles=soup.find_all(class_="pc_temp_songname")
# times=soup.find_all(class_="pc_temp_time")
# except:
# print("位置定位失败")
#
#
"""打印信息时,供select和find_all共同使用,find方法需写在try里面,因为多了一个if判断,层级下了一级"""
for num,title,time in zip(nums,titles,times):
data={"排名":num.get_text().replace('\n','').replace('\t','').replace('\r',''),
"歌手-歌名":title["title"],
"播放时间":time.string.replace('\n','').replace('\t','').replace('\r',''),
"网址":title["href"]}
print(data)
def main():
"""主接口"""
urls=["https://www.kugou.com/yy/rank/home/{}-6666.html?from=rank".format(str(i)) for i in range(1,10)]
for url in urls:
get_html(url)
html=get_html(url)
get_infos(html)
if __name__ == '__main__':
main()