爬取b站视频的名称、地址、简介、观看次数、弹幕数量及发布时间并导入到csv中(附csv文件乱码解决方法)

该爬虫大致分为以下步骤:

0.搜索关键词、点击搜索、进入新页面
1.获取每个页面的HTML
2.解析每个页面的HTML
3.将爬取到的数据写入csv文件

(这里搜索的例子是华晨宇,爬取前5页)

因为刚学爬虫,所以注释会写得比较多,方便自己理解。

文章末尾有完整源代码,分析过程的代码比较杂。


先引入相关模块、做好准备工作:

import requests
from bs4 import BeautifulSoup
from selenium import webdriver # 引入浏览器驱动
from selenium.webdriver.common.by import By # 借助By模块进行操作
from selenium.webdriver.support.ui import WebDriverWait # 显式等待
from selenium.webdriver.support import expected_conditions as Ec # 显式等待的条件
from selenium.common.exceptions import TimeoutException # 捕获超时异常
import pandas as pd


browser = webdriver.Chrome() # 获取浏览器对象
WAIT = WebDriverWait(browser,10) # 指定最长等待时间


url = 'https://www.bilibili.com'
print('开始访问b站……')
browser.get(url)

0.搜索关键词、点击搜索、进入新页面:

首先我们按F12观察一下b站页面的搜索框和搜索按键:


这里我们使用XPath选取节点,右键点击框起来的标签选择Copy XPath。

def search(content):
    print('正在进行搜索……')
    # 用XPath选取节点
    input = WAIT.until(Ec.presence_of_element_located((By.XPATH,'//*[@id="nav_searchform"]/input')))
    submit = WAIT.until(Ec.element_to_be_clickable((By.XPATH,'//*[@id="nav_searchform"]/div/button')))

    # 从搜索框输入并点击搜索
    input.send_keys(content)
    submit.click()

1. 获取每个页面的HTML:

首先我们搜索华晨宇,打开第二页:
在这里插入图片描述
我们看到在URL的末尾有一个关于页数的标记,所以我们使用for循环配合f+字符串的语句来格式化:

for i in range(5):
        # 用f+字符串来表示每一个页面的网址
        url = f"https://search.bilibili.com/all?keyword=%E5%8D%8E%E6%99%A8%E5%AE%87&from_source=nav_search_new&page={str(int(i+1))}"

这个步骤的代码为:

def crawl():
    htmls = [] # 存放每个页面的HTML
    # 用for循环爬取每一个页面并获得其HTML
    for i in range(5):
        # 用f+字符串来表示每一个页面的网址
        url = f"https://search.bilibili.com/all?keyword=%E5%8D%8E%E6%99%A8%E5%AE%87&from_source=nav_search_new&page={str(int(i+1))}"
        r = requests.get(url) # 返回Response对象
        if r.status_code != 200: # 状态码检测
            raise Exception("error")
        htmls.append(r.text) # r.text是字符串类型

    return htmls

2. 解析每个页面的HTML:

这时我们已经完成了搜索的操作,接下来按F12:
在这里插入图片描述


然后找到每个视频的HTML内容,我们使用find和find_all函数进行查找(返回的是列表):

def parse(htmls):
    videos = [] # 存放每个视频解析出来的HTML
    print('解析页面中……')
    for html in htmls:
        soup = BeautifulSoup(html, 'html.parser') # 解析每个页面
        # 获取每个视频的标签树
        video = soup.find(class_ = "video-list clearfix").find_all(class_="video-item matrix")
        videos.extend(video) # 列表存入列表,所以用extend()函数

接下来查找每个视频的名称、地址、简介、观看次数、弹幕数量及发布时间的HTML内容:
在这里插入图片描述
我们以第一个视频为例,可以看出视频的名称是a标签的title属性,地址是href属性,简介在有属性class="des hide"的标签的NavigableString(非属性字符串)元素中,而观看次数、弹幕数量及发布时间也类似,这里我找到class=“so-icon watch-num”、class=“so-icon time”、class="so-icon hide"对应的标签并用get_text()的方法获取目标路径下的子孙字符串(或者你找到i标签,用.string方法获取也可以,这里尝试多一种方法)。


完整的parse函数代码:

def parse(htmls):
    videos = [] # 存放每个视频解析出来的HTML
    print('解析页面中……')
    for html in htmls:
        soup = BeautifulSoup(html, 'html.parser') # 解析每个页面
        # 获取每个视频的标签树
        video = soup.find(class_ = "video-list clearfix").find_all(class_="video-item matrix")
        videos.extend(video) # 列表存入列表,所以用extend()函数

    items = [] # 存放每个视频的各个项目
    print('正在爬取相关信息……')
    for video in videos:
        item = {} # 每个字典存放每个视频的相关信息
        item['视频标题'] = video.find('a')['title'] # 获取标签属性
        item['视频地址'] = video.find('a')['href']
        item['简介'] = video.find(class_ = 'des hide').string # 获取NavigableString
        item['观看次数'] = video.find(class_ = 'so-icon watch-num').get_text() # 获取目标路径下的子孙字符串
        item['发布时间'] = video.find(class_ = 'so-icon time').get_text()
        item['弹幕数量'] = video.find(class_ = 'so-icon hide').get_text()
        items.append(item) # 字典存入列表,所以用append()函数
        
    return items

3.将爬取到的数据写入csv文件:

这里用pandas库的DataFrame方法构造一个数据框,然后写入csv文件:

def save_to_csv(items):
    print('成功将数据写入文件!')
    # 将爬取的数据写入csv文件
    df = pd.DataFrame(items) # 用DataFrame构造数据框
    df.to_csv("华晨宇.csv")

主函数:

def main():
    try:
        search('华晨宇')
        htmls = crawl()
        items = parse(htmls)
        save_to_csv(items)
    finally:
        print('爬取信息成功!')
        browser.close()


if __name__ == '__main__':
    main()

完整源代码:

import requests
from bs4 import BeautifulSoup
from selenium import webdriver # 引入浏览器驱动
from selenium.webdriver.common.by import By # 借助By模块进行操作
from selenium.webdriver.support.ui import WebDriverWait # 显式等待
from selenium.webdriver.support import expected_conditions as Ec # 显式等待的条件
from selenium.common.exceptions import TimeoutException # 捕获超时异常
import pandas as pd


browser = webdriver.Chrome() # 获取浏览器对象
WAIT = WebDriverWait(browser,10) # 指定最长等待时间


url = 'https://www.bilibili.com'
print('开始访问b站……')
browser.get(url)


def search(content):
    print('正在进行搜索……')
    # 用XPath选取节点
    input = WAIT.until(Ec.presence_of_element_located((By.XPATH,'//*[@id="nav_searchform"]/input')))
    submit = WAIT.until(Ec.element_to_be_clickable((By.XPATH,'//*[@id="nav_searchform"]/div/button')))

    # 从搜索框输入并点击搜索
    input.send_keys(content)
    submit.click()


def crawl():
    htmls = [] # 存放每个页面的HTML
    # 用for循环爬取每一个页面并获得其HTML
    for i in range(5):
        # 用f+字符串来表示每一个页面的网址
        url = f"https://search.bilibili.com/all?keyword=%E5%8D%8E%E6%99%A8%E5%AE%87&from_source=nav_search_new&page={str(int(i+1))}"
        r = requests.get(url) # 返回Response对象
        if r.status_code != 200: # 状态码检测
            raise Exception("error")
        htmls.append(r.text) # r.text是字符串类型

    return htmls

def parse(htmls):
    videos = [] # 存放每个视频解析出来的HTML
    print('解析页面中……')
    for html in htmls:
        soup = BeautifulSoup(html, 'html.parser') # 解析每个页面
        # 获取每个视频的标签树
        video = soup.find(class_ = "video-list clearfix").find_all(class_="video-item matrix")
        videos.extend(video) # 列表存入列表,所以用extend()函数

    items = [] # 存放每个视频的各个项目
    print('正在爬取相关信息……')
    for video in videos:
        item = {} # 每个字典存放每个视频的相关信息
        item['视频标题'] = video.find('a')['title'] # 获取标签属性
        item['视频地址'] = video.find('a')['href']
        item['简介'] = video.find(class_ = 'des hide').string # 获取NavigableString
        item['观看次数'] = video.find(class_ = 'so-icon watch-num').get_text() # 获取目标路径下的子孙字符串
        item['发布时间'] = video.find(class_ = 'so-icon time').get_text()
        item['弹幕数量'] = video.find(class_ = 'so-icon hide').get_text()
        items.append(item) # 字典存入列表,所以用append()函数
        
    return items


def save_to_csv(items):
    print('成功将数据写入文件!')
    # 将爬取的数据写入csv文件
    df = pd.DataFrame(items) # 用DataFrame构造数据框
    df.to_csv("华晨宇.csv")


def main():
    try:
        search('华晨宇')
        htmls = crawl()
        items = parse(htmls)
        save_to_csv(items)
    finally:
        print('爬取信息成功!')
        browser.close()


if __name__ == '__main__':
    main()

我们运行一下代码:

在这里插入图片描述
爬取成功!接下来我们看一下我们的csv文件:

在这里插入图片描述
打开它:

在这里插入图片描述

发现显示乱码……


解决方法:

我们用记事本打开该csv文件:
在这里插入图片描述
然后另存为,同时编码方式选择带有 BOM 的 UTF-8:

在这里插入图片描述
再次打开该csv文件,乱码问题就解决了:

在这里插入图片描述

发布了6 篇原创文章 · 获赞 13 · 访问量 370

猜你喜欢

转载自blog.csdn.net/weixin_45961774/article/details/104326779
今日推荐