排行榜html源码_Python爬虫爬取B站排行榜数据

论坛 期权论坛 脚本     
已经匿名di用户   2022-4-26 15:52   3922   0

目录

  • 写在前文
  • 获取网页数据
  • 提取数据
  • 整合并保存数据
  • 运行结果

点击此处,获取海量Python学习资料!

写在前文

在这篇博客中,我们将会从头开始实现完整的python简单爬虫项目。爬虫是一门高深的学问,这里说的简单爬虫是指获取的数据为静态网页数据,选择B站也是因为作者本身也是老二刺猿了,同时B站没有严格的反爬虫措施,适合新手的爬虫练手。由于本人第一次写博客,在编写的过程中难免会出现错误,如有发现错误或者不合理之处,欢迎到评论区留言指正~

获取网页数据

我们要爬取的内容是B站上的热门视频排行榜(全站版)

090819ef680a8e95326517b8392fd0e9.png

首先我们获取网页内容,为此需要构造网页网址url和请求头heqders。由于我使用的是谷歌浏览器,不同浏览器之间的使用方法可能会有些不同,这里以谷歌浏览器为例。
首先按F12打开控制台,然后依次点击Network、Doc,之后刷新页面,就会出现如下面图展示的内容:

54fe9eb3c2479724717e13ef169dc753.png


从内容中可以看到,网页的url为:

‘https://www.bilibili.com/ranking?spm_id_from=333.851.b_7072696d61727950616765546162.3’

接着下拉进度条,最后有一个user-agent,这便是headers需要的参数了。

user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36

在得到了url和headers后,便可以获取网页内容了,本文使用python的requests模块进行爬虫。代码如下:

import requests
url =  r'https://www.bilibili.com/ranking?spm_id_from=333.851.b_7072696d61727950616765546162.3'
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'}
data = []
response = requests.get(url,headers=headers)
if response.status_code == 200:
 data = response.content.decode('utf-8') 
else:
    print('网页解析失败')

提取数据

在前面的步骤中,我们利用requests库的get函数成功获取网页数据,那么如何从网页书中提取我们想要的数据呢?这里介绍一下Beautiful Soup。Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式,Beautiful Soup会帮你节省数小时甚至数天的工作时间。更详细的内容可以查看Beautiful Soup的官方中文网址。
1、第一步我们先解析获取的网页数据,使用lxml格式

soup = BeautifulSoup(data,'lxml')

2、经过Beautiful Soup解析后的数据,和我们在网页上看到的网页源代码应该是一样的,在谷歌浏览器上右键有一个“查看网页原代码选项”,点击后会跳转后HTML格式的网页代码端。

3、获取“视频标题”、“视频综合得分”、“视频播放量”、“视频评论数”、“up主名字”等数据
这里以网页源代码中的一小段数据进行展示,数据如下:

'''
</div></div><!----></div></li><li data-id="414452358" data-rank="4" class="rank-item">
<div class="num">4</div><div class="content"><div class="img">
<a href="https://www.bilibili.com/video/BV1UV41127Pc" target="_blank">
<div class="lazy-img cover">
<img alt="靠谱盘点93:破防成功?LEC解说开团乌兹不行,不好意思,又是三比零的一年!" src="">
</div></a><div class="watch-later-trigger w-later"></div></div><div class="info">
<a href="https://www.bilibili.com/video/BV1UV41127Pc" target="_blank" class="title">
靠谱盘点93:破防成功?LEC解说开团乌兹不行,不好意思,又是三比零的一年!</a><!---->
<div class="detail"><span class="data-box"><i class="b-icon play"></i>194.9万</span>
<span class="data-box"><i class="b-icon view"></i>1.5万</span>
<a target="_blank" href="//space.bilibili.com/279991456"><span class="data-box">
<i class="b-icon author"></i>靠谱电竞</span></a></div><div class="pts"><div>1939047</div>综合得分
'''  

(1) 获取视频标题
在上面的数据中,可以看到视频标题数据是存放在“title”这个class中,为此我们利用Beautiful Soup中的find()函数可以找到这个class,find_all()函数用于找到所有符合输入形式的数据。找到数据之后我们再用get_text()函数获取文本。需要注意的是find_all函数返回的是ResultSet格式的数据,我们需要对里面的每一个元素使用get_text()

video_names = []
namelist = soup.find_all(class_='title')
for name in namelist:
 video_names.append(name.get_text('title'))

(2) 获取视频综合得分
和上面获取视频标题的方法类似,视频综合得分数据存放于“pts”这个class中,因此方法完全一致

video_scores = []
scorelist = soup.find_all(class_='pts')
for score in scorelist:
 video_scores.append(score.get_text().replace('综合得分n','').strip())

(3) 获取视频播放量、评论数、up主名字
播放量、评论数、up主名字都是放在“data-box”这个class中,为了减少代码的冗余,这里放在一起一并处理。

video_play = []
video_comment = []
up_name = []
messages = soup.find_all(class_='data-box')
for i in range(0,len(messages),3):
 video_play.append(messages[i].get_text())
    video_comment.append(messages[i+1].get_text())
    up_name.append(messages[i+2].get_text())

(4) 获取视频排名
视频排名无非是1到100的数字,这里无需使用上面的方法了。因为我们爬下来的数据已经是按照顺序排列规整的,所以我们直接构造排名列表即可。

rank = [i for i in range(1,101,1)]

(5) 获取视频BV
这部分的数据比较难获取,主要原因是B站上源码里出现了两次视频地址,如果按照前面的方法,会提取到两个同样的视频地址。这里便需要字符串去重的方法了,需要保留字符顺序的同时并且实现去重的功能,这里我使用了for循环的方法

mess=[]
video_id = []
for value in soup.find_all('a'):
 mess.append(value.get('href'))
for i in range(len(mess)):
    if type(mess[i]) != str:
     pass
    elif mess[i].startswith('https://www.bilibili.com/video/'):
        video_id.append(mess[i].strip('https://www.bilibili.com/video/)'))
    else:
        pass
video_ids = []
for i in video_id:
 if not i in video_ids:
  video_ids.append(i)

整合并保存数据

经过上面的步骤,我们已经得到了所有需要的数据,接下来便是整合的过程,我们将得到的数据写成一个字典的形式。

import requests
from bs4 import BeautifulSoup
import pandas as pd
import datetime

def GetWeb(url=None, headers=None):
    '''
    此函数用于获取网页内容
    
    input
    url:网页的url
    headers:网页请求头
    
    retrun
    soup:经过Beautiful Soup解析后的数据
    '''
    data = []
    response = requests.get(url,headers=headers)
    if response.status_code == 200:
        data = response.content.decode('utf-8')
        soup = BeautifulSoup(data,'lxml')
        return soup
    else:
        print('网页解析失败')
        return None
        

def GetMess(soup):
    '''
    此函数用来从网页中提取需要的数据
    
    input
    soup:Beautiful Soup解析的数据
    
    return
    videodata:字典形式的数据,里面包含:视频标题、视频综合得分、
              视频播放量、视频评论数、up主名字、视频BV等数据
    '''
    video_names = []        # 视频标题
    video_scores = []       # 视频综合得分
    video_play = []         # 视频播放量
    video_comment = []      # 视频评论数
    up_name = []            # up主名字
    mess=[]                 # 视频地址
    video_id = []           # 视频BV
 
    # 对视频标题的处理
    namelist = soup.find_all('a',class_='title')
    for name in namelist:
        video_names.append(name.get_text('title'))
    
    # 对视频综合得分数据的处理
    scorelist = soup.find_all(class_='pts')
    for score in scorelist:
        video_scores.append(score.get_text().replace('综合得分n','').strip())
    
    # 对视频播放量、评论数、up主名字的处理
    messages = soup.find_all(class_='data-box')
    for i in range(0,len(messages),3):
        video_play.append(messages[i].get_text())
        video_comment.append(messages[i+1].get_text())
        up_name.append(messages[i+2].get_text())
    
    # 对视频id的处理
    for value in soup.find_all('a'):
        mess.append(value.get('href'))
    for i in range(len(mess)):
        if type(mess[i]) != str:
            pass
        elif mess[i].startswith('https://www.bilibili.com/video/'):
            video_id.append(mess[i].strip('https://www.bilibili.com/video/)'))
        else:
            pass
    video_ids = []
    for i in video_id:
        if not i in video_ids:
            video_ids.append(i)
    
    # 视频排名
    rank = [i for i in range(1,101,1)]
    
    # 打包整理成一个字典
    videodata = {'视频名字':video_names,
                 '播放量':video_play,
                 '评论数':video_comment,
                 '综合得分':video_scores,
                 'up主名字':up_name,
                 '视频BV':video_ids,
                 '排名':rank
            }
    
    return videodata
    
    
def SaveToExcel(videodata):
    
    try:
        VideoData = pd.DataFrame(videodata)
        VideoData.to_excel('B站排名前100的视频汇总({0}).xls'.format(datetime.datetime.now().strftime('%Y-%m-%d')),index=False)
        print('数据保存成功,请到文件“B站排名前100的视频汇总({0}).xls”中查看'.format(datetime.datetime.now().strftime('%Y-%m-%d')))
    except:
        print('数据写入失败')

def main():
    
    url =  r'https://www.bilibili.com/ranking?spm_id_from=333.851.b_7072696d61727950616765546162.3'
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
        }
    soup = GetWeb(url=url, headers=headers)
    videodata = GetMess(soup)
    SaveToExcel(videodata)

 
if __name__ == '__main__':
    main()

运行结果

46b65642211ffb7c049afd18b8a3ebc7.png

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP