基于selenium的视频爬取


前言

本项目为本人今年爬虫课程的期末程序设计,为记录自己的学习过程,故将项目发表在博客,以便自己日后回顾


一、selenium是什么?

Selenium是一个用于自动化web浏览器操作的开源工具套件。它支持各种浏览器(包括Chrome、Firefox、Safari等),允许用户编写脚本来模拟用户与web页面的交互,如点击按钮、填写表单、滚动页面等。Selenium主要用于web应用程序的测试,但也可以用于其他目的,如网络爬虫、自动化数据收集等。


二、项目步骤

1.引入库

项目需要的库

import random
import re
import threading
import requests  # 导入requests模块
import pymysql # 使用mysql数据库
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.options import Options

from proxy_ip.tool import readaproxy 
# 此处引入为自己创建的一个获取代理ip的函数

2.网页分析

通过开发者工具调试网页,发现视频数据在一个Ajax发送链接返回的json结果中。

在这里插入图片描述

在这里插入图片描述
故现在思路确定:通过request.get()向该Ajax的url发送请求获取到数据,再通过解析数据,拼凑出视频链接的url(视频链接为,https://www.dongchedi.com/video/ + json的data[‘data’][‘news’][页数][‘unique_id_str’]构成),最后通过selenium访问该url获取到数据进行本地下载,并将视频详细数据存储在数据库中。

3.selenium爬取方法的设计

其中使用无头,禁止图片css加载和禁用gpu是为了加快selenium运行速度。

def seleunim_(url, title):
    '''
    用于自动化获取视频链接并下载到本地video文件夹中
    :param url: 爬取网址
    :param title: 视频标题
    :return:
    '''
    # 创建Chrome浏览器选项对象
    opt = Options()
    # 使用无头模式
    opt.add_argument('--headless')

    # 禁止图片和css加载
    prefs = {"profile.managed_default_content_settings.images": 2, 'permissions.default.stylesheet': 2}
    opt.add_experimental_option("prefs", prefs)

    opt.add_argument("--disable-gpu")  # 禁用gpu 
    pa = webdriver.Chrome(options=opt)

    # 开始
    pa.get(url)
    pa.delete_all_cookies()  # 删除网页之前的cookie

    time.sleep(0.7)
    print(f'正在下载{title}')
    element = pa.find_element(By.XPATH,
                              "/html/body/div[1]/div/div/div/div/div[1]/div[1]/div/div[1]/div/div/div/video")  # 找到视频链接元素
    result = requests.get(element.get_attribute('src'))

    # 对标题进行处理 防止打开文件时出错
    title = sanitize_filename(title)
    # 保存视频链接到文件中
    with open(f"video/{title}.mp4", "wb") as f:
        f.write(result.content)
    print('-------' + title + '----下载成功')
    pa.quit()

为了防止标题出现非法的字符导致保存文件出现错误,对标题进行预处理。

def sanitize_filename(title):
    # 使用正则表达式来匹配并移除非法字符
    sanitized = re.sub(r'[\\/*?"<>|:#.?\x00-\x1f]', '', title)

    # 移除空格
    sanitized = sanitized.replace(' ', '')

    # 去除字符串两端的空白字符(包括空格、制表符、换行符等)
    sanitized = sanitized.strip()

    # 确保文件名不会过长
    max_length = 255  # 例如,Windows中某些文件系统的最大路径长度为260个字符,文件名长度会受此限制

    sanitized = sanitized[:max_length]

    return sanitized

4.数据库相关的准备

创建一个简单的表,其中:
detail_context:视频详细内容
title:视频标题
num:数据编号(唯一性)

在这里插入图片描述

插入数据库的方法设计。

def insert(context, title):
    # 设置布尔标记,成功返回1,失败返回0
    tag = 1

    db = pymysql.connect(
        host='localhost',
        user='root',
        password='liweijiaw',
        port=3306,
        db='dongchedi_vediodata'
    )# 数据库信息

    cursor = db.cursor() # 启动数据库引擎
    sql = 'INSERT INTO vedio_data (detail_context,title) VALUES ("%s","%s");'

    try:
        cursor.execute(sql, (context, title)) # 执行sql语句
        db.commit()

    except pymysql.Error as e:
        print(e.args[0], e.args[1])
        db.rollback() # 回滚
        print('数据库fail')
        tag = 0  # 失败设置0

    db.close()
    return tag

5.主函数设计

最大特点是使用了多线程爬取,这样一次性就可以下载多个视频,提高爬取效率。

if __name__ == '__main__':

    # 响应头池
    headers_stack = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
        "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
        "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
        "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
    ]

    # 找到ajax发送的url,
    url = ('https://www.dongchedi.com/motor/pc/content/get_static?'
           'aid=1839&app_name=auto_web_pc&count=100&channel=news&page=1&article_type=video')

    # 随机获取一个User-Agent
    headers = {"User-Agent": headers_stack[random.randint(0, 4)]}

    # 随机从数据库中获取一个可用的代理ip
    proxy = {"http": readaproxy()[0]}

    # 解析返回的数据包 (数据包是json格式)
    response = requests.get(url, headers=headers, proxies=proxy, timeout=3)
    data = response.json()  # 解析json文件

    for i in range(1, 6):  # 1 to 6 exclude 6.
        # 内容(将字典转为string类型,以免发生不必要的错误)
        context = str(data['data']['news'][i])
        # 解析获取标题
        title = str(data['data']['news'][i]['title'])
        # 插入数据库
        if insert(context, title) == 0: print(f'{title}插入失败!')
        # 获取视频链接
        vedio_url = str(('https://www.dongchedi.com/video/'
                         + data['data']['news'][i]['unique_id_str']))

        while threading.active_count() > 4:  # 限制一次性只能下载四个视频,当大于四个视频在下载时,会卡在循环里等待
            print(f'当前正有{threading.active_count() - 1}个视频在下载,等待中.......')  # -1代表不包括主进程
            time.sleep(8)

        # 获取视频(通过观察发现视频页面为为https://www.dongchedi.com/video+"unique_id_str")由于网页是动态加载的,所以使用selenuim获取
        thread = threading.Thread(target=seleunim_, args=(vedio_url, title))  # 使用多线程技术,一次性爬取多个视频
        thread.start()
        print('线程启动')

        time.sleep(0.5)  # 这里休眠的作用是因为如果循环太快,将会大于四个线程被启动(循环的速度大于while判断的速度)

6.项目运行展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值