Python项目实战哔哩哔哩用户抓取及源码

Posted 日常分享Python

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python项目实战哔哩哔哩用户抓取及源码相关的知识,希望对你有一定的参考价值。

目录

文件介绍

用户数据初步分析

基本概况

性别

年龄

地区

注册时间

活跃度统计

粉丝统计

源码:

源码太多啦,想要获取完整的源码可以戳这里


本文所使用的数据可视化为infogr.am

该爬虫仅供学习使用

文件介绍

  • bilibili_user.py:爬虫文件
  • bilibili_user_info.sql:数据库文件
  • get_face.py:用户头像下载器

 

用户数据初步分析

基本概况

  • 总数据数:20119918
  • 抓取用户的顺序为其注册时间顺序:2009-06-24 14:06:54 至 2016-02-18 21:04:52
  • 预估遗漏数据:不超过2%
  • 抓取字段:用户id,昵称,性别,头像,等级,经验值,粉丝数,生日,地址,注册时间,签名,等级与经验值等。

性别

  • 有效数据:14643019
  • 保密:11621898
  • 男:1674196
  • 女:1346925

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d736578312e706e672d3630302e6a7067

这个男女比例是有点出乎个人预料的,接近1:1。其实之前初步抓了2013年暑假之前的数据,男女比例当时还在3:1这样。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d736578322e706e672d3630302e6a7067

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d736578332e706e672d3630302e6a7067

可见明确性别的群体还是比较少的,只占了总数据的 15% 左右。

更多的分析日后再做。

年龄

  • 统计范围:1970-2010(1980年除外)
  • 总数据:3800767

具体数据不放了,简单看一下统计结果吧。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d616765332e706e672d3630302e6a7067

主要用户分布在93-00年的用户(大概16-23周岁),其中97年(19岁)用户占了绝对的主导地位。

事实证明,B站小学生并不多,而是高中生、大学生比较多。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d616765312e706e672d3630302e6a7067

 

90后用户占主体,但是用户年龄段正在不断后移。毕竟,是一个年轻人的网站。

地区

  • 分析范围:国内34个省市及地区。
  • 有效数据:863541

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d706c616365312e706e672d3630302e6a7067

主要用户分布在:广东、江苏、北京、上海、浙江等地区。都是一些经济很发达的沿海地区。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d706c616365332e706e672d3630302e6a7067

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d706c616365322e706e672d3630302e6a7067

注册时间

  • 统计时间:2009-06-24 14:06:54 至 2016-02-18 21:04:52
  • 总数据:20119823

注册时间统计

由于16年才过去2个多月,所以少一点,不过可以预见其发展必将远超2015年。自2009年开站以来,每年用户几乎都是以指数级增长。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d726567322e706e672d3630302e6a7067

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d726567332e706e672d3630302e6a7067

活跃度统计

  • 等级范围:0 - 6
  • 总数据:20119918
  • 截止时间:2016-02-18

由于B站有经验等级规则,用户的活跃度可以依据等级判断。

等级为0,就是只注册未登陆过的用户。等级为1或2,为非活跃用户。等级为3以上,就是活跃用户。其中等级为5或6的,为投稿数特别特别多、视频特别火爆的用户,为B站的主干用户(约5000人)。

等级统计

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d6c6576656c322e706e672d3630302e6a7067

关于留存率等数据,日后再统计分析。

粉丝统计

  • 有效数据:2011918
  • 范围:0 - 988323
  • 截止时间:2016-02-18 21:04:52

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d66616e73312e706e672d3630302e6a7067

哎- -,我也是有2个粉丝的人!

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d66616e73342e706e672d3630302e6a7067

以下是B站TOP20用户。很多人都非常的眼熟哈。

687474703a2f2f616972696e672e757273622e6d652f7572736262696c6962696c692d66616e73332e706e672d3630302e6a7067

源码:

# -*-coding:utf8-*-

import requests
import json
import random
import pymysql
import sys
import datetime
import time
from imp import reload
from multiprocessing.dummy import Pool as ThreadPool

def datetime_to_timestamp_in_milliseconds(d):
    def current_milli_time(): return int(round(time.time() * 1000))
    return current_milli_time()
reload(sys)


def LoadUserAgents(uafile):
    uas = []
    with open(uafile, 'rb') as uaf:
        for ua in uaf.readlines():
            if ua:
                uas.append(ua.strip()[:-1])
    random.shuffle(uas)
    return uas


uas = LoadUserAgents("user_agents.txt")
head = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'Referer': 'http://space.bilibili.com/45388',
    'Origin': 'http://space.bilibili.com',
    'Host': 'space.bilibili.com',
    'AlexaToolbar-ALX_NS_PH': 'AlexaToolbar/alx-4.0',
    'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4',
    'Accept': 'application/json, text/javascript, */*; q=0.01',
}

# Please replace your own proxies.
proxies = {
    'http': 'http://120.26.110.59:8080',
    'http': 'http://120.52.32.46:80',
    'http': 'http://218.85.133.62:80',
}
time1 = time.time()

urls = []


# Please change the range data by yourself.
for m in range(5214, 5215):

    for i in range(m * 100, (m + 1) * 100):
        url = 'https://space.bilibili.com/' + str(i)
        urls.append(url)


    def getsource(url):
        payload = {
            '_': datetime_to_timestamp_in_milliseconds(datetime.datetime.now()),
            'mid': url.replace('https://space.bilibili.com/', '')
        }
        ua = random.choice(uas)
        head = {
            'User-Agent': ua,
            'Referer': 'https://space.bilibili.com/' + str(i) + '?from=search&seid=' + str(random.randint(10000, 50000))
        }
        mid = payload['mid']

        #使用post会报错 (2021/5/2)
        jscontent = requests \\
          .session() \\
          .get('https://api.bilibili.com/x/space/acc/info?mid=%s&jsonp=jsonp' % mid,
                headers=head,
                data=payload
                ) \\
          .text

        time2 = time.time()
        try:
            jsDict = json.loads(jscontent)
            status_code = jsDict['code'] if 'code' in jsDict.keys() else False
            if status_code == 0:
                if 'data' in jsDict.keys():
                    jsData = jsDict['data']
                    mid = jsData['mid']
                    name = jsData['name']
                    sex = jsData['sex']
                    rank = jsData['rank']
                    face = jsData['face']
                    regtimestamp = jsData['jointime']
                    regtime_local = time.localtime(regtimestamp)
                    regtime = time.strftime("%Y-%m-%d %H:%M:%S", regtime_local)

                    birthday = jsData['birthday'] if 'birthday' in jsData.keys() else 'nobirthday'
                    sign = jsData['sign']
                    level = jsData['level']
                    OfficialVerifyType = jsData['official']['type']
                    OfficialVerifyDesc = jsData['official']['desc']
                    vipType = jsData['vip']['type']
                    vipStatus = jsData['vip']['status']
                    coins = jsData['coins']
                    print("Succeed get user info: " + str(mid) + "\\t" + str(time2 - time1))
                    try:
                        res = requests.get(
                            'https://api.bilibili.com/x/relation/stat?vmid=' + str(mid) + '&jsonp=jsonp').text
                        viewinfo = requests.get(
                            'https://api.bilibili.com/x/space/upstat?mid=' + str(mid) + '&jsonp=jsonp').text
                        js_fans_data = json.loads(res)
                        js_viewdata = json.loads(viewinfo)
                        following = js_fans_data['data']['following']
                        fans = js_fans_data['data']['follower']
                    except:
                        following = 0
                        fans = 0

                else:
                    print('no data now')
                try:
                    print(jsDict)
                    # Please write your MySQL's information.
                    conn = pymysql.connect(
                        host='localhost', user='root', passwd='123456', db='bilibili', charset='utf8')
                    cur = conn.cursor()
                    cur.execute('INSERT INTO bilibili_user_info(mid, name, sex, rank, face, regtime, \\
                                birthday, sign, level, OfficialVerifyType, OfficialVerifyDesc, vipType, vipStatus, \\
                                coins, following, fans) \\
                    VALUES ("%s","%s","%s","%s","%s","%s","%s","%s",\\
                            "%s","%s","%s","%s","%s", "%s","%s","%s")'
                                %
                                (mid, name, sex, rank, face, regtime, \\
                                 birthday, sign, level, OfficialVerifyType, OfficialVerifyDesc, vipType, vipStatus, \\
                                 coins, following, fans))
                    conn.commit()
                except Exception as e:
                    print(e)
            else:
                print("Error: " + url)
        except Exception as e:
            print(e)
            pass

if __name__ == "__main__":
    pool = ThreadPool(1)
    try:
        results = pool.map(getsource, urls)
    except Exception as e:
        print(e)
 
    pool.close()
    pool.join()

源码太多啦,想要获取完整的源码可以戳这里

以上如果想要操作一遍的或者想要代码的可以+关+私
或者+qq群聊 :222020937【既能学习也能接单,而且资料及视频代码也准备好了】 欢迎加入《广告勿加,不然你做啥啥不赚钱》

以上是关于Python项目实战哔哩哔哩用户抓取及源码的主要内容,如果未能解决你的问题,请参考以下文章

好课推荐Flutter高级进阶实战 仿哔哩哔哩APP~7百度网盘分享

在Python中用Request库模拟登录:哔哩哔哩(有加密,有验证码)

盘点大厂的那些开源项目 - 哔哩哔哩

哔哩哔哩的企业五要素

实习丨哔哩哔哩:后端开发

微信小程序项目(哔哩哔哩小程序)