【Python】哔哩哔哩视频下载第3篇:Beautifulsoup+requests+selenium获取大牛技术视频url

本系列文章旨在分享python学习的心得,所涉及的视频和up主皆是值得与大家分享的,如有冒犯,望请谅解。

本期任务:使用Python下载B站大佬投稿页所有视频

【Python】第1节:常规方法与you-get

【Python】第2节:进程池的应用

【Python】第3节:Beautifulsoup+requests+selenium获取视频url

【Python】第4节:常见问题的解决(2020年3月23日哔哩哔哩将稿件的「av 号」变更为「BV 号」)

完整GitHub代码:BilibiliDownloader

上一节,我们实现了用multiprocessing实现多进程调用you-get下载哔哩哔哩技术视频,解决了CPU和带宽利用率低的问题。
本节我们将介绍使用Beautifulsoup+requests+selenium,实现简单的爬虫,获取大牛技术视频url。

任务描述

本节我们将以CodeSheep(博主最喜欢的Java up主!!!)的投稿页的79个视频url为目标进行爬取。
难点:网页解析,动态加载(反爬机制)

完整代码

import os
import time

import requests
from bs4 import BeautifulSoup
from selenium import webdriver


# 给定哔哩哔哩up主投稿页链接,爬取所有视频链接
class RequestsSpider:
    def __init__(self, pages, **kwargs):
        self.depth = pages   # CodeSheep 投稿页功79个视频,分成3页
        if kwargs.get('selenium'):
            self.browser = self.selenium()

    def selenium(self):
        executable_path = r"输入chromedriver.exe的存放路径"
        chrome_options = webdriver.ChromeOptions()
        """后台运行Chromedriver"""
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        browser = webdriver.Chrome(executable_path=executable_path, chrome_options=chrome_options)

        """全屏显示"""
        browser.maximize_window()
        time.sleep(5)
        return browser

    def downloader1(self, url):
        “”“
		需动态加载时, 使用selenium加载完整页面再返回
	    ”“”
        self.browser.get(url)
        self.browser.implicitly_wait(20)
        time.sleep(5)
        return self.browser.page_source

    def downloader(self, url):
        “”“
		无需动态加载时,直接使用requests.get()获取页面
	    ”“”
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""

    def parse(self, info, html, **kwargs):
        """
            网页解析: BeautifulSoup + re
        """
        soup = BeautifulSoup(html, "html.parser")

        nodes = soup.find("ul", {"class": "clearfix cube-list"}).find_all("li")
        aids = [node.get("data-aid") for node in nodes]
        info.extend(aids)

    def spider(self):
        """
        初始url与调度
        """
        info = []
        start_url = "https://space.bilibili.com/384068749/video?tid=0&page=" # 投稿页的url

        for i in range(self.depth):
            print("正在爬取第{0}页".format(i + 1))
            try:
                url = start_url + str(i + 1)
                html = self.downloader1(url)
                self.parse(info, html)
            except Exception as e:
                print(e)
        return info


if __name__ == "__main__":
    client = RequestsSpider(pages=3, selenium=True)
    urls = client.spider()
    client.browser.close()
    urls = ["https://www.bilibili.com/video/av" + item for item in urls]
    print(urls)

核心部分讲解

注意:

  • 因为需要使用selenium进行动态加载,需要pip安装selenium(第三方库)
  • 本任务使用的是chrome驱动(还有Firfox、Edge等),需要自行下载与本机Chrome版本号相一致的驱动,版本一致!版本一致!版本一致!
  • 驱动下载传送门:Chrome驱动

RequestsSpider类:

实例化的时候,需要申明下载页数(pages),是否启用selenium进行动态加载(开启时爬虫效率一般远低于未开启状态)

    def __init__(self, pages, **kwargs):
        self.depth = pages   # CodeSheep 投稿页功79个视频,分成3页
        if kwargs.get('selenium'):
            self.browser = self.selenium()

selenium基本配置:什么驱动存放位置、后台静默运行、全屏显示等

 def selenium(self):
        executable_path = r"输入chromedriver.exe的存放路径"
        chrome_options = webdriver.ChromeOptions()
        """后台运行Chromedriver"""
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        browser = webdriver.Chrome(executable_path=executable_path, chrome_options=chrome_options)

        """全屏显示"""
        browser.maximize_window()
        time.sleep(5)
        return browser

使用selenium动态加载网页内容

    def downloader1(self, url):
        “”“
		需动态加载时, 使用selenium加载完整页面再返回
	    ”“”
        self.browser.get(url)
        self.browser.implicitly_wait(20)
        time.sleep(5)
        return self.browser.page_source

使用request.get()快速加载网页

	def downloader(self, url):
        “”“
		无需动态加载时,直接使用requests.get()获取页面
	    ”“”
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""

网页解析:
chrome浏览器,点击F12打开网页源代码,通过简单分析,可以发现,
我们需要的内容位于li标签内data-aid的属性值:如图中的"95417273", 其中li位于class为clearfix cube-list的ul标签下。
在这里插入图片描述
将selenium加载的页面用BeautifulSoup熬成一锅"soup",
按照上面的分析,找到class为"clearfix cube-list"的ul标签下的所有li标签;
将每个li标签中的"data-aid"对应的值保存到aids中
拓展info即可完成当前页面的解析。

    def parse(self, info, html, **kwargs):
        """
            网页解析: BeautifulSoup + re
        """
        soup = BeautifulSoup(html, "html.parser")

        nodes = soup.find("ul", {"class": "clearfix cube-list"}).find_all("li")
        aids = [node.get("data-aid") for node in nodes]
        info.extend(aids)

爬虫主逻辑:分析投稿页不同页面的url,总结url规律;循环调用download1动态加载,并调用parse解析网页内容,结果更新到info中

def spider(self):
        """
        初始url与调度
        """
        info = []
        start_url = "https://space.bilibili.com/384068749/video?tid=0&page=" # 投稿页的url

        for i in range(self.depth):
            print("正在爬取第{0}页".format(i + 1))
            try:
                url = start_url + str(i + 1)
                html = self.downloader1(url)
                self.parse(info, html)
            except Exception as e:
                print(e)
        return info

效果

在这里插入图片描述
接下来,便可以使用前两节的方法进行视频下载了。

温馨提醒:下载过程固然能学到一些东西,静心感悟大佬想传达的意义才是核心,不要满足于当搬运工,共勉。

下期预告

【Python】整理matplotlib绘图库,用新的方式解读pyplot绘图过程

原创文章 36 获赞 32 访问量 2757

猜你喜欢

转载自blog.csdn.net/weixin_43868754/article/details/104951951