python爬取b站排行榜

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

目的

b站是我平時看得最多的一個網站,最近接到了一個爬蟲的課設。首先要選擇一個網站,並對其進行爬取,最後將該網站的數據存儲並使其可視化。html

網站的結構

目標網站:bilibili排行榜

bilibili排行榜的地址mysql

網頁的層次

  1. 首先要肯定要提取的信息,也就是標題、播放量、做者up主、評分、播放量和評論量

  1. 在網頁源代碼中找到要找的信息

每一個網頁中大概有多條這樣的rank-item項目,要提取的信息就包含其中sql

<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標籤下數據庫

對應解析其的代碼app

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

網站的層次

經過觀察鏈接參數的變化ide

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

以這個連接爲例,經過實驗,該網頁連接的參數表明各類意義,ranking表明排行,all表明是不是全站仍是原創,第一個參數0表明,各個分區,第二個參數0表明了所有投稿仍是近期投稿,第三個參數3表明了是三日內投遞的,根據實驗規律,獲得了生成鏈接的代碼,可是隻有全站榜和原創榜支持這個規律,其餘的暫時沒爬fetch

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)
相關文章
相關標籤/搜索