Hugo Future Imperfect Slim

Xiang.Y

A bioinformation student

爬取B站UP主的部分信息

爬取B站UP主信息

Xiang.Y

2 minute read

Pic 1

爬取网页,一般的做法是先直接向目标页面发起请求,然后返回,查看返回页面是否与目标页面相同,如果不同,则证明这个页面是动态加载页面,需要另寻它法。

所以,我向B站发起了请求:https://space.bilibili.com/105511477

然而,返回的页面完全没有我需要的信息,这说明B站使用了异步加载技术,于是我逐个分析请求url,在https://api.bilibili.com/x/space/acc/info?mid=105511477&;jsonp=jsonp这个请求的响应中发现了id号, 姓名,性别, 生日,等级等数据,但是找不到关注数,粉丝数。继续分析,在https://api.bilibili.com/x/relation/stat?vmid=105511477&;jsonp=jsonp&callback=__jp3响应中找到关注数,粉丝数等数据。但是我嫌麻烦,直接在网上找到了将这2个url合并的url:https://api.bilibili.com/x/web-interface/card?mid=105511477&;jsonp=jsonp&article=true

直接发起请求,得到json数据,然后解析json数据就行了。由于B站数据太多,我有编写了进度保存与加载,防止重复爬取。但是爬取速度是比较慢的,改进的建议:多线程和分布式爬取。

由于数据不全,我没有做后续分析。

代码:

# -*- coding: utf-8 -*-
import requests
import json
import time

# 爬取B站up主的信息,包括:id号,姓名,性别,粉丝数,关注数,等级
# 由于B站数据太多,这里不能全部爬取,建议改进:多线程, 分布式
# 包含爬取数据进度保存,可以随时爬取


def get_html(url):  # 向网站发送请求,代码格式固定
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0'}
    cookie = {'Cookie': "fts=1504349387; buvid3=1C1CB246-90F7-4641-994C-875348FCC9DA31841infoc; LIVE_BUVID=923027b89ab5074df00ddeb74bd1bc4c; LIVE_PLAYER_TYPE=1; LIVE_BUVID__ckMd5=213686949aed5aa3; sid=jszx4g3e; stardustvideo=1; CURRENT_FNVAL=16; rpdid=kmwpioxopmdospssmioww; CURRENT_QUALITY=32; bp_t_offset_105511477=225519300968954321; finger=888236dc; im_notify_type_105511477=0; UM_distinctid=169200905bf184-0820062ee695d58-4c312f7f-100200-169200905c039c; DedeUserID=105511477; DedeUserID__ckMd5=e312e81cda67c220; SESSDATA=f560bc58%2C1553994772%2C44a40231; bili_jct=90910cb604d93fccf748794b4007ba13; bsource=seo_baidu; _dfcaptcha=d2c62b90ce5116dd8e1dd97aec364e73"}
    print(cookie)
    r = requests.get(url=url, headers=headers, cookies=cookie)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.content.decode()


def get_information(url):  # 得到页面信息
    html = get_html(url)  # 得到json
    value = json.loads(html)  # 加载json
    flag = True  # flag,判断是否有这个页面
    mid = value.get("data").get("card").get("mid")  # json得到mid号
    name = value.get("data").get("card").get("name")
    sex = value.get("data").get("card").get("sex")
    fans = value.get("data").get("card").get("fans")
    attention = value.get("data").get("card").get("attention")
    level = value.get("data").get("card").get("level_info").get("current_level")
    if mid == "":  # mid号为空,则没有这个用户
        flag = False
    return flag, mid, name, sex, fans, attention, level  # 返回信息


with open("test.txt", "a+", encoding="utf-8") as f, open("save.txt", "r+") as f1:
    start = int(f1.readline().strip().split("_")[-1])  # 加载保存的进度
    if start == 0:
        f.write("mid\tname\tsex\tfans\tattention\tlevel\n")  # 如果没有进度,则写出题头
    for i in range(start, 100000000):
        mid = i + 1
        # 生成url
        url = "https://api.bilibili.com/x/web-interface/card?mid=%d&jsonp=jsonp&article=true" % mid
        flag, mid, name, sex, fans, attention, level = get_information(url)  # 得到数据
        if flag:
            # 写出数据
            f.write(str(mid) + "\t" + name + "\t" + sex + "\t" + str(fans) + "\t" +
                    str(attention) + "\t" + str(level) + "\n")
        if i % 100 == 0:  # 每100轮保存进度
            f1.write("_" + mid)
            f.flush()
            f1.flush()
            print(i)
        time.sleep(0.1)  # 每次爬取后休息0.1秒





Recent posts

See more

Categories

About

Something to say