zoukankan      html  css  js  c++  java
  • python爬取b站排行榜

    爬取b站排行榜并存到mysql中

    目的

    b站是我平时看得最多的一个网站,最近接到了一个爬虫的课设。首先要选择一个网站,并对其进行爬取,最后将该网站的数据存储并使其可视化。

    网站的结构

    目标网站:bilibili排行榜

    bilibili排行榜的地址

    网页的层次

    1. 首先要确定要提取的信息,也就是标题、播放量、作者up主、评分、播放量和评论量

    1. 在网页源代码中找到要找的信息

    每个网页中大概有多条这样的rank-item项目,要提取的信息就包含其中

    <li class="rank-item">
         <div class="num">3</div>
             <div class="content">
               <div class="img">
               <a href="//bangumi.bilibili.com/anime/28016" target="_blank">
                       <div class="lazy-img cover"><img alt="女高中生的虚度日常" src=""></div>
               </a>
               <!---->
         </div>
           <div class="info">
               <a href="//bangumi.bilibili.com/anime/28016" target="_blank"class="title">
               女高中生的虚度日常
               </a>
           <div class="bangumi-info">全12话</div>
           <div class="detail">
           <span class="data-box">
               <i class="b-icon play"></i>
               3491.1万
           </span>
           <span class="data-box">
               <i class="b-icon view"></i>
               74.3万
           </span>
           <span class="data-box">
               <i class="fav">
               </i>
               176.4万
           </span></div>
           <div class="pts">
                 <div>2218000</div>综合得分
           </div>
       </div>                              
       </div>
    </li>
    

    1.名称在title类的a标签下
    2.播放量、评论数、和up主在data-box类的span标签下
    3.综合评分在pts类的div标签下

    对应解析其的代码

    def getPage(url):#爬取单个页面,核心代码
        spider=Spider(url)
        spider.setSoup()
        itemList=spider.findTagByAttrs('li','rank-item')
        pageContentList=[]
        for item in itemList:
            pageContentItem=[]
            for title in item.find_all('a','title'):
                pageContentItem.append(title.string)
                # print(title.string)
                
            for playnum in item.find_all('span','data-box'):
                pattern=r">([^<]+)<"
                n=re.findall(pattern,playnum.__str__())[0]
                pageContentItem.append(n)
                # print(n)
            
                
            # print(item.find_all('div','pts')[0].div.string)
            pageContentItem.append(item.find_all('div','pts')[0].div.string)
            pageContentList.append(pageContentItem)
        return pageContentList     
    
    

    网站的层次

    通过观察连接参数的变化

    https://www.bilibili.com/ranking/all/0/0/3
    

    以这个链接为例,通过实验,该网页链接的参数代表各种意义,ranking代表排行,all代表是否是全站还是原创,第一个参数0代表,各个分区,第二个参数0代表了全部投稿还是近期投稿,第三个参数3代表了是三日内投递的,根据实验规律,得到了生成连接的代码,但是只有全站榜和原创榜支持这个规律,其他的暂时没爬

    def getURLFormBilibili():# 获取各种各样排行的榜单的信息
        date={
            1:'日排行',
            3:'三日排行',
            7:'周排行',
            30:'月排行'
        }
        areatype={
            0:'全站',
            1:'动画',
            168:'国漫相关',
            3:'音乐',
            129:'舞蹈',
            4:'游戏',
            36:'科技',
            188:'数码',
            160:'生活',
            119:'鬼畜',
            155:'时尚',
            5:'娱乐',
            181:'影视'
        }
        ranktype={
           'all':'全站',
           'origin':'原创'
        }
        submit={
            '0':'全部投稿',
            '1':'近期投稿'
        }
        urlDict={}#存放相应url的字典
        for ranktypeItem in ranktype.keys():
            for areatypeItem in areatype.keys():
                for submitItem in submit.keys():
                    for dateTypeItem in date.keys():
                        title=ranktype[ranktypeItem]+'_'+areatype[areatypeItem]+'_'+submit[submitItem]+'_'+date[dateTypeItem]
                        destinaTionUrl='https://www.bilibili.com/ranking/{}/{}/{}/{}'.format(ranktypeItem,areatypeItem,submitItem,dateTypeItem)
                        urlDict[title]=destinaTionUrl
        return urlDict
    
    

    保存到mysql数据库

    这里使用了pymysql这个库,安装使用pip就好了,就不再赘述,为了方便我把它写成了一个类

        
    class MysqlConnect:#数据库的连接类
        def __init__(self):
            pass
        
        def getConnect(self):
            db=coon = pymysql.connect(
                host = 'localhost',user = 'root',passwd = '你的密码',
                port = 3306,db = 'bilibilirank',charset = 'utf8'
                 #port必须写int类型
                 #charset必须写utf8,不能写utf-8
            )
            return db
            
        def insertInfo(self,sql):
            db=self.getConnect()
            cursor=db.cursor()
            try:
                cursor.execute(sql)
                db.commit()
                print("sucessed...")
            except:
                print("failed...")
                db.rollback()
                
        
        def queryOutCome(self,sql):
             # 获取数据库连接  
            db = self.getConnect()  
            # 使用cursor() 方法创建一个游标对象 cursor  
            cursor = db.cursor()  
            try:  
                # 执行sql语句  
                cursor.execute(sql)  
                result = cursor.fetchone()  
            except: #方法二:采用traceback模块查看异常  
                #输出异常信息  
                traceback.print_exc()  
                # 如果发生异常,则回滚  
                db.rollback()  
            finally:  
                # 最终关闭数据库连接  
                db.close()  
            return result  
        
        def getCreateTableSql(self,tableName):#获取创建表的sql语句
            sql='''
            create table `{}` (
                id int(11) auto_increment primary key,
                title char(100) NOT NULL UNIQUE,
                playnum char(100) NOT NULL,
                commentnum char(100) NOT NULL,
                author char(100) NOT NULL,
                score char(100) NOT NULL
            )ENGINE=innodb DEFAULT CHARSET=utf8;
            '''.format(tableName)
            return sql
            
        def getInsertToTableSql(self,tableName,title,playnum,commentnum,author,score):
            sql='''
            insert into `{}` values(null,'{}','{}','{}','{}','{}');
            '''.format(tableName,title,playnum,commentnum,author,score)
            return sql
            
            
        
        def createTable(self,tableName,sql):
            db=self.getConnect()
            cursor=db.cursor()
            cursor.execute("drop table if exists %s" %(tableName)) 
            cursor.execute(sql)
            db.close()
    

    爬取数据

    按照页面逐个爬取保存到数据库

    if __name__ == "__main__":
        #开始爬取数据
        urlDict=getURLFormBilibili()#获取对应的URL信息
        mysqlconnect=MysqlConnect()#用于连接数据库
        
        for urlName in urlDict:
            print("正在处理"+urlName+"页面...")
            url=urlDict[urlName]
            tableName=urlName
            createsql=mysqlconnect.getCreateTableSql(tableName)
            mysqlconnect.createTable(tableName,createsql)
            pageList=getPage(url)
            for contentItem in pageList:
                insertsql=mysqlconnect.getInsertToTableSql(tableName,contentItem[0],contentItem[1],contentItem[2],contentItem[3],contentItem[4])
                print(insertsql)
                mysqlconnect.insertInfo(insertsql)
    

    结果

    源代码

    import requests
    import re
    from bs4 import BeautifulSoup
    import pymysql
    import traceback
    
    class Spider:#常用的爬取方法的简单封装
        def __init__(self,url):
            self.url=url
            
        def getHTML(self):#获取html的对应代码
            headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.103 Safari/537.36'}
            try:
                response=requests.get(url=self.url,headers=headers,timeout=20)
                response.raise_for_status()
                response.encoding=response.apparent_encoding
                return response.text
            except:
                return "网页访问失败"
            
            
        def setSoup(self):#获取soup对象
            html=self.getHTML()
            self.soup=BeautifulSoup(html,'html.parser')
        
        def findTag(self,tagName):#按照标签名查找标签
            return self.soup.find_all(tagName)
        
        def findTagByAttrs(self,tagName,attrs):
            return self.soup.find_all(tagName,attrs)
    
        
        def getBeautifyHTML(self):
            return self.soup.prettify()
    
    
    def getPage(url):#爬取单个页面,核心代码
        spider=Spider(url)
        spider.setSoup()
        itemList=spider.findTagByAttrs('li','rank-item')
        pageContentList=[]
        for item in itemList:
            pageContentItem=[]
            for title in item.find_all('a','title'):
                pageContentItem.append(title.string)
                # print(title.string)
                
            for playnum in item.find_all('span','data-box'):
                pattern=r">([^<]+)<"
                n=re.findall(pattern,playnum.__str__())[0]
                pageContentItem.append(n)
                # print(n)
            
                
            # print(item.find_all('div','pts')[0].div.string)
            pageContentItem.append(item.find_all('div','pts')[0].div.string)
            pageContentList.append(pageContentItem)
        return pageContentList     
    
    
    def getURLFormBilibili():# 获取各种各样排行的榜单的信息
        date={
            1:'日排行',
            3:'三日排行',
            7:'周排行',
            30:'月排行'
        }
        areatype={
            0:'全站',
            1:'动画',
            168:'国漫相关',
            3:'音乐',
            129:'舞蹈',
            4:'游戏',
            36:'科技',
            188:'数码',
            160:'生活',
            119:'鬼畜',
            155:'时尚',
            5:'娱乐',
            181:'影视'
        }
        ranktype={
           'all':'全站',
           'origin':'原创'
        }
        submit={
            '0':'全部投稿',
            '1':'近期投稿'
        }
        urlDict={}#存放相应url的字典
        for ranktypeItem in ranktype.keys():
            for areatypeItem in areatype.keys():
                for submitItem in submit.keys():
                    for dateTypeItem in date.keys():
                        title=ranktype[ranktypeItem]+'_'+areatype[areatypeItem]+'_'+submit[submitItem]+'_'+date[dateTypeItem]
                        destinaTionUrl='https://www.bilibili.com/ranking/{}/{}/{}/{}'.format(ranktypeItem,areatypeItem,submitItem,dateTypeItem)
                        urlDict[title]=destinaTionUrl
        return urlDict
    
        
        
    class MysqlConnect:#数据库的连接类
        def __init__(self):
            pass
        
        def getConnect(self):
            db=coon = pymysql.connect(
                host = 'localhost',user = 'root',passwd = '你的密码',
                port = 3306,db = 'bilibilirank',charset = 'utf8'
                 #port必须写int类型
                 #charset必须写utf8,不能写utf-8
            )
            return db
            
        def insertInfo(self,sql):
            db=self.getConnect()
            cursor=db.cursor()
            try:
                cursor.execute(sql)
                db.commit()
                print("sucessed...")
            except:
                print("failed...")
                db.rollback()
                
        
        def queryOutCome(self,sql):
             # 获取数据库连接  
            db = self.getConnect()  
            # 使用cursor() 方法创建一个游标对象 cursor  
            cursor = db.cursor()  
            try:  
                # 执行sql语句  
                cursor.execute(sql)  
                result = cursor.fetchone()  
            except: #方法二:采用traceback模块查看异常  
                #输出异常信息  
                traceback.print_exc()  
                # 如果发生异常,则回滚  
                db.rollback()  
            finally:  
                # 最终关闭数据库连接  
                db.close()  
            return result  
        
        def getCreateTableSql(self,tableName):#获取创建表的sql语句
            sql='''
            create table `{}` (
                id int(11) auto_increment primary key,
                title char(100) NOT NULL UNIQUE,
                playnum char(100) NOT NULL,
                commentnum char(100) NOT NULL,
                author char(100) NOT NULL,
                score char(100) NOT NULL
            )ENGINE=innodb DEFAULT CHARSET=utf8;
            '''.format(tableName)
            return sql
            
        def getInsertToTableSql(self,tableName,title,playnum,commentnum,author,score):
            sql='''
            insert into `{}` values(null,'{}','{}','{}','{}','{}');
            '''.format(tableName,title,playnum,commentnum,author,score)
            return sql
            
            
        
        def createTable(self,tableName,sql):
            db=self.getConnect()
            cursor=db.cursor()
            cursor.execute("drop table if exists %s" %(tableName)) 
            cursor.execute(sql)
            db.close()
    
    
    if __name__ == "__main__":
        #开始爬取数据
        urlDict=getURLFormBilibili()#获取对应的URL信息
        mysqlconnect=MysqlConnect()#用于连接数据库
        
        for urlName in urlDict:
            print("正在处理"+urlName+"页面...")
            url=urlDict[urlName]
            tableName=urlName
            createsql=mysqlconnect.getCreateTableSql(tableName)
            mysqlconnect.createTable(tableName,createsql)
            pageList=getPage(url)
            for contentItem in pageList:
                insertsql=mysqlconnect.getInsertToTableSql(tableName,contentItem[0],contentItem[1],contentItem[2],contentItem[3],contentItem[4])
                print(insertsql)
                mysqlconnect.insertInfo(insertsql)
            
    
    
  • 相关阅读:
    [POJ1743]Musical Theme
    ubuntu qq
    Separate code and data contexts: an architectural approach to virtual text sharing
    Python3发送post请求,自动记住cookie
    python 异步协程
    豆瓣爬虫
    pandas 使用
    房天下爬虫
    计算英文文章词频的两种方法
    LOW版统计词频
  • 原文地址:https://www.cnblogs.com/mengxiaoleng/p/11598832.html
Copyright © 2011-2022 走看看