1. 为什么需要批量采集B站视频信息

最近在做市场调研时,我发现手动收集B站视频数据实在太费时间了。每次搜索关键词后,都要一页页翻看,记录视频标题、播放量这些基础信息。特别是当需要分析某个垂直领域的内容趋势时,这种手工操作方式简直让人崩溃。

这时候就需要用到自动化采集技术了。通过编写爬虫程序,我们可以快速获取B站搜索结果页的视频信息。比如你想了解"人工智能"相关视频的播放量分布,或者想分析某个UP主的内容发布规律,批量采集数据就能帮上大忙。

XPath作为XML路径语言,特别适合用来解析HTML文档结构。相比正则表达式,它的语法更直观,定位元素也更精准。我在实际项目中测试过,用XPath提取B站视频信息,代码可读性和稳定性都比其他方法要好。

2. 准备工作与环境搭建

2.1 必备工具清单

在开始写代码前,我们需要准备好这些工具:

  • Python 3.6+(推荐3.8版本)
  • requests库(用于发送HTTP请求)
  • lxml库(解析HTML和XPath处理)
  • pandas库(数据存储和处理)

安装这些库很简单,用pip一行命令就能搞定:

pip install requests lxml pandas

2.2 分析B站页面结构

打开B站搜索页面,按F12进入开发者工具。这里有个小技巧:点击开发者工具左上角的箭头图标,然后鼠标悬停在页面元素上,就能自动定位到对应的HTML代码。

我注意到B站的搜索结果页有几个特点:

  1. 视频卡片都包含在class为"bili-video-card"的div中
  2. 第一页和第二页的DOM结构有细微差异
  3. 分页参数是通过URL的query string控制的

3. XPath定位实战技巧

3.1 基础定位方法

在开发者工具中,右键点击元素选择"Copy XPath"可以快速获取定位路径。但直接复制的XPath往往过于具体,容易受页面结构调整影响。我建议使用相对路径和属性组合的方式。

比如获取视频标题,可以用:

//div[contains(@class,'bili-video-card')]//h3/@title

这样即使外层容器变化,只要class名称不变,定位依然有效。

3.2 处理动态分页

B站的搜索结果页有个特点:第一页的URL结构和其他页不同。经过测试,我发现分页规律是这样的:

第一页URL示例:

https://search.bilibili.com/all?keyword=人工智能

第二页开始会添加page参数:

https://search.bilibili.com/all?keyword=人工智能&page=2

在代码中需要做判断处理:

if 'page=' not in url:
    # 第一页的特殊处理
    items = bs.xpath('//div[@id="search-result"]//div[contains(@class,"video-card")]')
else:
    # 其他页的通用处理
    items = bs.xpath('//div[contains(@class,"video-list")]//div[contains(@class,"video-card")]')

4. 完整代码实现与优化

4.1 基础采集框架

先来看核心代码结构:

import requests
from lxml import etree
import pandas as pd

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}

def parse_page(url):
    html = requests.get(url, headers=headers).text
    bs = etree.HTML(html)
    
    # 这里放XPath提取逻辑
    videos = []
    
    return videos

def main():
    base_url = "https://search.bilibili.com/all?keyword={keyword}&page={page}"
    keyword = "人工智能"
    
    all_videos = []
    for page in range(1, 6):  # 采集前5页
        url = base_url.format(keyword=keyword, page=page)
        videos = parse_page(url)
        all_videos.extend(videos)
    
    df = pd.DataFrame(all_videos)
    df.to_excel("b站视频数据.xlsx", index=False)

4.2 异常处理与反爬策略

在实际运行中,我发现几个需要注意的问题:

  1. 请求频率控制:连续快速请求容易被封,建议添加随机延迟
import time
import random

time.sleep(random.uniform(1, 3))  # 1-3秒随机延迟
  1. 元素缺失处理:不是所有视频都有弹幕数等信息
try:
    barrage = item.xpath('.//span[contains(@class,"barrage")]/text()')[0]
except IndexError:
    barrage = '0'
  1. 代理设置:如果IP被封,可以考虑使用代理池
proxies = {
    'http': 'http://your_proxy:port',
    'https': 'https://your_proxy:port'
}
response = requests.get(url, headers=headers, proxies=proxies)

5. 数据处理与存储优化

5.1 数据清洗技巧

采集到的原始数据往往需要清洗:

# 处理播放量字符串(如"12.3万"转成123000)
def clean_play_count(text):
    if '万' in text:
        return int(float(text.replace('万','')) * 10000)
    return int(text)

df['播放量'] = df['播放量'].apply(clean_play_count)

5.2 存储方案选择

根据数据量大小,可以考虑不同存储方式:

  1. 小数据量(<1万条):Excel或CSV
  2. 中等数据量:SQLite
  3. 大数据量:MySQL或MongoDB

我常用的CSV存储代码:

import csv

with open('data.csv', 'w', newline='', encoding='utf-8-sig') as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(data)

6. 项目实战经验分享

在实际项目中,我遇到过几个典型问题:

  1. XPath失效:B站前端改版导致定位失效。解决方案是使用更宽松的定位策略,比如用contains()匹配class名而不是完整路径。

  2. 分页中断:有时采集到第5页就停止了。后来发现是因为页码参数有特殊处理,需要在URL中添加"&o=xxx"参数。

  3. 数据不全:部分视频信息加载较慢。可以尝试添加等待时间或使用Selenium等工具。

一个健壮的采集脚本应该包含这些功能:

  • 自动重试机制
  • 断点续采功能
  • 日志记录系统
  • 数据去重处理

最后提醒一点,采集数据时要注意遵守网站的使用条款,控制请求频率,避免对服务器造成过大压力。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐