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

目的

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

网站的结构

目标网站:bilibili排行榜

bilibili排行榜的地址

网页的层次

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

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

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

  1. <li class="rank-item">
  2. <div class="num">3</div>
  3. <div class="content">
  4. <div class="img">
  5. <a href="//bangumi.bilibili.com/anime/28016" target="_blank">
  6. <div class="lazy-img cover"><img alt="女高中生的虚度日常" src=""></div>
  7. </a>
  8. <!---->
  9. </div>
  10. <div class="info">
  11. <a href="//bangumi.bilibili.com/anime/28016" target="_blank"class="title">
  12. 女高中生的虚度日常
  13. </a>
  14. <div class="bangumi-info">全12话</div>
  15. <div class="detail">
  16. <span class="data-box">
  17. <i class="b-icon play"></i>
  18. 3491.1万
  19. </span>
  20. <span class="data-box">
  21. <i class="b-icon view"></i>
  22. 74.3万
  23. </span>
  24. <span class="data-box">
  25. <i class="fav">
  26. </i>
  27. 176.4万
  28. </span></div>
  29. <div class="pts">
  30. <div>2218000</div>综合得分
  31. </div>
  32. </div>
  33. </div>
  34. </li>

1.名称在title类的a标签下

2.播放量、评论数、和up主在data-box类的span标签下

3.综合评分在pts类的div标签下

对应解析其的代码

  1. def getPage(url):#爬取单个页面,核心代码
  2. spider=Spider(url)
  3. spider.setSoup()
  4. itemList=spider.findTagByAttrs('li','rank-item')
  5. pageContentList=[]
  6. for item in itemList:
  7. pageContentItem=[]
  8. for title in item.find_all('a','title'):
  9. pageContentItem.append(title.string)
  10. # print(title.string)
  11. for playnum in item.find_all('span','data-box'):
  12. pattern=r">([^<]+)<"
  13. n=re.findall(pattern,playnum.__str__())[0]
  14. pageContentItem.append(n)
  15. # print(n)
  16. # print(item.find_all('div','pts')[0].div.string)
  17. pageContentItem.append(item.find_all('div','pts')[0].div.string)
  18. pageContentList.append(pageContentItem)
  19. return pageContentList

网站的层次

通过观察连接参数的变化

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

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

  1. def getURLFormBilibili():# 获取各种各样排行的榜单的信息
  2. date={
  3. 1:'日排行',
  4. 3:'三日排行',
  5. 7:'周排行',
  6. 30:'月排行'
  7. }
  8. areatype={
  9. 0:'全站',
  10. 1:'动画',
  11. 168:'国漫相关',
  12. 3:'音乐',
  13. 129:'舞蹈',
  14. 4:'游戏',
  15. 36:'科技',
  16. 188:'数码',
  17. 160:'生活',
  18. 119:'鬼畜',
  19. 155:'时尚',
  20. 5:'娱乐',
  21. 181:'影视'
  22. }
  23. ranktype={
  24. 'all':'全站',
  25. 'origin':'原创'
  26. }
  27. submit={
  28. '0':'全部投稿',
  29. '1':'近期投稿'
  30. }
  31. urlDict={}#存放相应url的字典
  32. for ranktypeItem in ranktype.keys():
  33. for areatypeItem in areatype.keys():
  34. for submitItem in submit.keys():
  35. for dateTypeItem in date.keys():
  36. title=ranktype[ranktypeItem]+'_'+areatype[areatypeItem]+'_'+submit[submitItem]+'_'+date[dateTypeItem]
  37. destinaTionUrl='https://www.bilibili.com/ranking/{}/{}/{}/{}'.format(ranktypeItem,areatypeItem,submitItem,dateTypeItem)
  38. urlDict[title]=destinaTionUrl
  39. return urlDict

保存到mysql数据库

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


  1. class MysqlConnect:#数据库的连接类
  2. def __init__(self):
  3. pass
  4. def getConnect(self):
  5. db=coon = pymysql.connect(
  6. host = 'localhost',user = 'root',passwd = '你的密码',
  7. port = 3306,db = 'bilibilirank',charset = 'utf8'
  8. #port必须写int类型
  9. #charset必须写utf8,不能写utf-8
  10. )
  11. return db
  12. def insertInfo(self,sql):
  13. db=self.getConnect()
  14. cursor=db.cursor()
  15. try:
  16. cursor.execute(sql)
  17. db.commit()
  18. print("sucessed...")
  19. except:
  20. print("failed...")
  21. db.rollback()
  22. def queryOutCome(self,sql):
  23. # 获取数据库连接
  24. db = self.getConnect()
  25. # 使用cursor() 方法创建一个游标对象 cursor
  26. cursor = db.cursor()
  27. try:
  28. # 执行sql语句
  29. cursor.execute(sql)
  30. result = cursor.fetchone()
  31. except: #方法二:采用traceback模块查看异常
  32. #输出异常信息
  33. traceback.print_exc()
  34. # 如果发生异常,则回滚
  35. db.rollback()
  36. finally:
  37. # 最终关闭数据库连接
  38. db.close()
  39. return result
  40. def getCreateTableSql(self,tableName):#获取创建表的sql语句
  41. sql='''
  42. create table `{}` (
  43. id int(11) auto_increment primary key,
  44. title char(100) NOT NULL UNIQUE,
  45. playnum char(100) NOT NULL,
  46. commentnum char(100) NOT NULL,
  47. author char(100) NOT NULL,
  48. score char(100) NOT NULL
  49. )ENGINE=innodb DEFAULT CHARSET=utf8;
  50. '''.format(tableName)
  51. return sql
  52. def getInsertToTableSql(self,tableName,title,playnum,commentnum,author,score):
  53. sql='''
  54. insert into `{}` values(null,'{}','{}','{}','{}','{}');
  55. '''.format(tableName,title,playnum,commentnum,author,score)
  56. return sql
  57. def createTable(self,tableName,sql):
  58. db=self.getConnect()
  59. cursor=db.cursor()
  60. cursor.execute("drop table if exists %s" %(tableName))
  61. cursor.execute(sql)
  62. db.close()

爬取数据

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

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

结果

源代码

  1. import requests
  2. import re
  3. from bs4 import BeautifulSoup
  4. import pymysql
  5. import traceback
  6. class Spider:#常用的爬取方法的简单封装
  7. def __init__(self,url):
  8. self.url=url
  9. def getHTML(self):#获取html的对应代码
  10. 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'}
  11. try:
  12. response=requests.get(url=self.url,headers=headers,timeout=20)
  13. response.raise_for_status()
  14. response.encoding=response.apparent_encoding
  15. return response.text
  16. except:
  17. return "网页访问失败"
  18. def setSoup(self):#获取soup对象
  19. html=self.getHTML()
  20. self.soup=BeautifulSoup(html,'html.parser')
  21. def findTag(self,tagName):#按照标签名查找标签
  22. return self.soup.find_all(tagName)
  23. def findTagByAttrs(self,tagName,attrs):
  24. return self.soup.find_all(tagName,attrs)
  25. def getBeautifyHTML(self):
  26. return self.soup.prettify()
  27. def getPage(url):#爬取单个页面,核心代码
  28. spider=Spider(url)
  29. spider.setSoup()
  30. itemList=spider.findTagByAttrs('li','rank-item')
  31. pageContentList=[]
  32. for item in itemList:
  33. pageContentItem=[]
  34. for title in item.find_all('a','title'):
  35. pageContentItem.append(title.string)
  36. # print(title.string)
  37. for playnum in item.find_all('span','data-box'):
  38. pattern=r">([^<]+)<"
  39. n=re.findall(pattern,playnum.__str__())[0]
  40. pageContentItem.append(n)
  41. # print(n)
  42. # print(item.find_all('div','pts')[0].div.string)
  43. pageContentItem.append(item.find_all('div','pts')[0].div.string)
  44. pageContentList.append(pageContentItem)
  45. return pageContentList
  46. def getURLFormBilibili():# 获取各种各样排行的榜单的信息
  47. date={
  48. 1:'日排行',
  49. 3:'三日排行',
  50. 7:'周排行',
  51. 30:'月排行'
  52. }
  53. areatype={
  54. 0:'全站',
  55. 1:'动画',
  56. 168:'国漫相关',
  57. 3:'音乐',
  58. 129:'舞蹈',
  59. 4:'游戏',
  60. 36:'科技',
  61. 188:'数码',
  62. 160:'生活',
  63. 119:'鬼畜',
  64. 155:'时尚',
  65. 5:'娱乐',
  66. 181:'影视'
  67. }
  68. ranktype={
  69. 'all':'全站',
  70. 'origin':'原创'
  71. }
  72. submit={
  73. '0':'全部投稿',
  74. '1':'近期投稿'
  75. }
  76. urlDict={}#存放相应url的字典
  77. for ranktypeItem in ranktype.keys():
  78. for areatypeItem in areatype.keys():
  79. for submitItem in submit.keys():
  80. for dateTypeItem in date.keys():
  81. title=ranktype[ranktypeItem]+'_'+areatype[areatypeItem]+'_'+submit[submitItem]+'_'+date[dateTypeItem]
  82. destinaTionUrl='https://www.bilibili.com/ranking/{}/{}/{}/{}'.format(ranktypeItem,areatypeItem,submitItem,dateTypeItem)
  83. urlDict[title]=destinaTionUrl
  84. return urlDict
  85. class MysqlConnect:#数据库的连接类
  86. def __init__(self):
  87. pass
  88. def getConnect(self):
  89. db=coon = pymysql.connect(
  90. host = 'localhost',user = 'root',passwd = '你的密码',
  91. port = 3306,db = 'bilibilirank',charset = 'utf8'
  92. #port必须写int类型
  93. #charset必须写utf8,不能写utf-8
  94. )
  95. return db
  96. def insertInfo(self,sql):
  97. db=self.getConnect()
  98. cursor=db.cursor()
  99. try:
  100. cursor.execute(sql)
  101. db.commit()
  102. print("sucessed...")
  103. except:
  104. print("failed...")
  105. db.rollback()
  106. def queryOutCome(self,sql):
  107. # 获取数据库连接
  108. db = self.getConnect()
  109. # 使用cursor() 方法创建一个游标对象 cursor
  110. cursor = db.cursor()
  111. try:
  112. # 执行sql语句
  113. cursor.execute(sql)
  114. result = cursor.fetchone()
  115. except: #方法二:采用traceback模块查看异常
  116. #输出异常信息
  117. traceback.print_exc()
  118. # 如果发生异常,则回滚
  119. db.rollback()
  120. finally:
  121. # 最终关闭数据库连接
  122. db.close()
  123. return result
  124. def getCreateTableSql(self,tableName):#获取创建表的sql语句
  125. sql='''
  126. create table `{}` (
  127. id int(11) auto_increment primary key,
  128. title char(100) NOT NULL UNIQUE,
  129. playnum char(100) NOT NULL,
  130. commentnum char(100) NOT NULL,
  131. author char(100) NOT NULL,
  132. score char(100) NOT NULL
  133. )ENGINE=innodb DEFAULT CHARSET=utf8;
  134. '''.format(tableName)
  135. return sql
  136. def getInsertToTableSql(self,tableName,title,playnum,commentnum,author,score):
  137. sql='''
  138. insert into `{}` values(null,'{}','{}','{}','{}','{}');
  139. '''.format(tableName,title,playnum,commentnum,author,score)
  140. return sql
  141. def createTable(self,tableName,sql):
  142. db=self.getConnect()
  143. cursor=db.cursor()
  144. cursor.execute("drop table if exists %s" %(tableName))
  145. cursor.execute(sql)
  146. db.close()
  147. if __name__ == "__main__":
  148. #开始爬取数据
  149. urlDict=getURLFormBilibili()#获取对应的URL信息
  150. mysqlconnect=MysqlConnect()#用于连接数据库
  151. for urlName in urlDict:
  152. print("正在处理"+urlName+"页面...")
  153. url=urlDict[urlName]
  154. tableName=urlName
  155. createsql=mysqlconnect.getCreateTableSql(tableName)
  156. mysqlconnect.createTable(tableName,createsql)
  157. pageList=getPage(url)
  158. for contentItem in pageList:
  159. insertsql=mysqlconnect.getInsertToTableSql(tableName,contentItem[0],contentItem[1],contentItem[2],contentItem[3],contentItem[4])
  160. print(insertsql)
  161. mysqlconnect.insertInfo(insertsql)

python爬取b站排行榜的更多相关文章

  1. python爬取b站排行榜视频信息

    和上一篇相比,差别不是很大 import xlrd#读取excel import xlwt#写入excel import requests import linecache import wordcl ...

  2. 萌新学习Python爬取B站弹幕+R语言分词demo说明

    代码地址如下:http://www.demodashi.com/demo/11578.html 一.写在前面 之前在简书首页看到了Python爬虫的介绍,于是就想着爬取B站弹幕并绘制词云,因此有了这样 ...

  3. 用Python爬取B站、腾讯视频、爱奇艺和芒果TV视频弹幕!

    众所周知,弹幕,即在网络上观看视频时弹出的评论性字幕.不知道大家看视频的时候会不会点开弹幕,于我而言,弹幕是视频内容的良好补充,是一个组织良好的评论序列.通过分析弹幕,我们可以快速洞察广大观众对于视频 ...

  4. python爬取某站新闻,并分析最近新闻关键词

    在爬取某站时并做简单分析时,遇到如下问题和大家分享,避免犯错: 一丶网站的path为 /info/1013/13930.htm ,其中13930为不同新闻的 ID 值,但是这个数虽然为升序,但是没有任 ...

  5. 用python爬取B站在线用户人数

    最近在自学Python爬虫,所以想练一下手,用python来爬取B站在线人数,应该可以拿来小小分析一下 设计思路 首先查看网页源代码,找到相应的html,然后利用各种工具(BeautifulSoup或 ...

  6. Python爬取B站视频信息

    该文内容已失效,现已实现scrapy+scrapy-splash来爬取该网站视频及用户信息,由于B站的反爬封IP,以及网上的免费代理IP绝大部分失效,无法实现一个可靠的IP代理池,免费代理网站又是各种 ...

  7. Python爬取b站任意up主所有视频弹幕

    爬取b站弹幕并不困难.要得到up主所有视频弹幕,我们首先进入up主视频页面,即https://space.bilibili.com/id号/video这个页面.按F12打开开发者菜单,刷新一下,在ne ...

  8. Python爬取B站耗子尾汁、不讲武德出处的视频弹幕

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 前言 耗子喂汁是什么意思什么梗呢?可能很多人不知道,这个梗是出自马保国,经常上网的人可能听说过这个 ...

  9. 使用python爬取P站图片

    刚开学时有一段时间周末没事,于是经常在P站的特辑里收图,但是P站加载图片的速度比较感人,觉得自己身为计算机专业,怎么可以做一张张图慢慢下这么low的事,而且这样效率的确也太低了,于是就想写个程序来帮我 ...

随机推荐

  1. react在视频中截图,保存为base64位

    wq:之前看了网上很多教程,有点模糊,但是最后还是搞了出来 1  不要将视频放到canvas上面!  之前一直将video重新画到canvas上面,然后再次将第一个canvas放到第二个canvas上 ...

  2. oracle基本语句(第五章、数据库逻辑存储结构管理)

    1.使用SYS用户以SYSDBA身份登录到SQL Plus,使用视图V$TABLESPACE查看表空间信息 SELECT * FROM V$TABLESPACE; 2.查看视图DBA_TABLESPA ...

  3. 【NOIP2016提高A组模拟8.23】函数

    题目 分析 观察这个是式子\(\sum_{d|n}f(n)=n\), 发现其实函数\(f()\)就是欧拉函数\(φ()\)(见http://blog.csdn.net/chen1352/article ...

  4. 【leetcode】1185. Day of the Week

    题目如下: Given a date, return the corresponding day of the week for that date. The input is given as th ...

  5. linux RPM(红帽软件包管理器)和Yum软件仓库中常见的命令

    RPM(红帽软件包管理器)常用命令 安装软件:rpm -ivh filename.rpm 升级软件:rpm -Uvh filename.rpm 卸载软件:rpm -e filename.rpm 查询软 ...

  6. ClustrixDB安装配置

    前提条件 在安装ClustrixDB之前,需要: ClustrixDB安装程序和许可证密钥. 运行CentOS或RHEL 7.4的服务器(本地或云中). 具有root或sudo特权来安装Clustri ...

  7. tomcat7 与tomcat8 使用tomcat dbcp pool注意对应类变化

    tomcat dbcp pool在tomcat 7 和tomcat8下的jar包有变化,相应包名也发生变化,对应类名有相应变化! tomcat的lib文件夹下会有jar包tomcat-dbcp.jar ...

  8. Egret Tween

    最近开始接触Egret,其实也就是为了写一些小的特效 1.egret.Tween.get() ,激活一个对象,对其添加 Tween 动画 2.to() ,将指定对象的属性修改为指定值 egret.Tw ...

  9. Python实现人脸识别

    识别图片 #coding=utf-8 import requests,cv2 import re import os import bs4 #2.读取图片 filename = 'E:/Python/ ...

  10. leetcode 234 回文链表 Palindrome Linked List

    要求用O(n)时间,和O(1)空间,因此思路是用本身链表进行判断,既然考虑回文,本方法思想是先遍历一次求链表长度,然后翻转前半部分链表:然后同时对前半部分链表和后半部分链表遍历,来判断对应节点的值是否 ...