Airtest-Selenium实操小课②:刷B站视频
1. 前言
上一课我们讲到用Airtest-Selenium爬取网站上我们需要的信息数据,还没看的同学可以戳这里看看~
那么今天的推文,我们就来说说看,怎么实现看b站、刷b站的日常操作,包括点击暂停,发弹幕,点赞,收藏等操作,仅供大家参考学习~
2.需求分析和准备
整体的需求大致可以分为以下步骤:
- 打开chrome浏览器
- 打开百度网页
- 搜索“哔哩哔哩”
- 点击进入“哔哩哔哩”官网
- 搜索关键词“Airtest酱”
- 点击进入“Airtest酱”首页,随机点击播放视频
- 并对视频点击暂停,发弹幕,点赞,收藏
在写脚本之前,我们需要准备好社区版AirtestIDE(目前最新版为1.2.16),设置好chrome.exe地址和对应的driver;并且确保我们的chrome浏览器版本不是太高以及selenium是4.0以下即可(这些兼容问题我们都会在后续的版本修复)。
3. 脚本实现与运行效果
3.1 脚本运行效果
我们在编写这次代码的时候,我们主要是使用了页面元素定位的方式去进行操作交互的,除此之外还实现了保存cookie、读取cookie的一个操作。大家在日常使用也会发现,在首次通过脚本开启的chrome网页界面是无cookie的,那么我们在进行一些任务之前是需要先登录后才能进行下一步操作的,可以通过首次登录时读取cookie数据保存到本地,往后每次运行只需要读取本地的cookie文件就可以轻松登录啦~
先来看下我们整体的运行效果:
Airtest-selenium实现自动化刷b站
3.2 完整代码分享
这里也附上完整的示例代码给大家参考,有需要的同学可以自取学习哦:
# -*- encoding=utf8 -*-
from airtest.core.api import *
# 引入selenium的webdriver模块
from airtest_selenium.proxy import WebChrome
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import threading
import time
import random
import json#保存以及调用cookie的线程
class UtilFunc():def cookie_is_exist_(self, cook_name='_'): # 检查txt文件是否存在if os.path.exists(f'{cook_name}cookies.txt'):return Truereturn Falsedef cookie_save_(self, driver, cook_name='_'): #保存cookie到txt文件中以便下次读取# 获取当前页面的所有cookiecookies = driver.get_cookies()# 将cookie转换为JSON字符串cookies_json = json.dumps(cookies)# 保存cookie到txt文件with open(f'{cook_name}cookies.txt', 'w') as file:file.write(cookies_json)print(f"保存cookies:{cookies}")def cookie_set_(self, driver, cook_name='_'): #读取cookie文件并给当前网站设置已存cookie# 从txt文件读取JSON_cookie数据with open(f'{cook_name}cookies.txt', 'r', encoding='gbk') as file:json_data = file.read()# 将JSON数据转换为列表data_list = json.loads(json_data)for cookie in data_list:driver.add_cookie(cookie)print("设置cookie")# 创建一个实例,代码运行到这里,会打开一个chrome浏览器
driver = WebChrome()
isLogin = False #存储登录状态值,False为未登录,True为已登录#打开chrome浏览器并打开视频播放
def start_selenium():driver.implicitly_wait(20)driver.get("https://www.baidu.com/")# 输入搜索关键词并提交搜索search_box = driver.find_element_by_name('wd')search_box.send_keys('哔哩哔哩')search_box.submit()try:# 查找搜索结果中文本为 "哔哩哔哩" 的元素并点击results = driver.find_elements_by_xpath('//div[@id="content_left"]//span[contains(text(), "哔哩哔哩")]')if results:results[0].click()print("点击了哔哩哔哩搜索结果")except Exception as e:element = driver.find_element_by_xpath("//div[@id='content_left']/div[@id='1']/div[@class='c-container']/div[1]/h3[@class='c-title t t tts-title']/a")element.click()driver.switch_to_new_tab() # 切换界面util_cookie = UtilFunc()if util_cookie.cookie_is_exist_("Airtest酱登录"): # 存在cookie文件,设置cookieutil_cookie.cookie_set_(driver, "Airtest酱登录")# 输入搜索关键词并提交搜索search_box = driver.find_element_by_class_name('nav-search-input')search_box.send_keys('Airtest酱')# 模拟发送Enter键search_box.send_keys(Keys.ENTER)sleep(5)driver.switch_to_new_tab() # 切换界面results_ = driver.find_elements_by_xpath('//div[@class="bili-video-card__info--right"]//span[contains(text(),"Airtest酱")]')if results_:results_[0].click()driver.switch_to_new_tab() # 切换界面driver.refresh()sleep(2)video_ele = driver.find_element_by_xpath("//div[@title='14天Airtest自动化测试小白课程']")# 滚动到指定元素处driver.execute_script("arguments[0].scrollIntoView(true);", video_ele)sleep(5)video_ele.click()driver.switch_to_new_tab() # 切换界面# 获取所有视频video_list = driver.find_elements_by_xpath("//ul[@class='row video-list clearfix']//a[@class='title']")random_element = random.choice(video_list)random_element.click() # 随机播放一个driver.switch_to_new_tab() # 切换界面#登录
def is_login():"""线程检测登录弹窗"""def is_no_login(*args):global isLogin # 在线程内修改外部常量的值no_login_tip = Truewhile True:element = driver.find_elements_by_css_selector('.bili-mini-content-wp')if len(element) > 0:if no_login_tip:print("未登录 请在五分钟内扫码")no_login_tip = Falseelse:print("未检测到登录弹窗")check_login_ele = driver.find_elements_by_css_selector('.bpx-player-dm-wrap')if not check_login_ele:isLogin = TrueUtilFunc().cookie_save_(driver, "Airtest酱登录")print("保存cookie")breaklog_text_array = [element.text for element in check_login_ele] # 使用列表推导式简化代码if "请先登录或注册" in log_text_array:loginbtn = driver.find_elements_by_xpath("//div[@class='bili-header fixed-header']//div[@class='header-login-entry']")if loginbtn:loginbtn[0].click()isLogin = Falseprint("判断cookie文件是否存在,方便下次调用,设置后刷新页面")else:isLogin = TrueUtilFunc().cookie_save_(driver, "Airtest酱登录")print("保存cookie")breakthread = threading.Thread(target=is_no_login, args=("args",))thread.start()#暂停播放
def video_pause_and_play(check_btn=False):if isLogin:try:paus_btn = driver.find_elements_by_xpath("//*[@id=\"bilibili-player\"]//div[@class='bpx-player-ctrl-btn bpx-player-ctrl-play']")if paus_btn[0]:detection_time1 = driver.find_elements_by_xpath('//*[@class="bpx-player-control-bottom-left"]//div[@class="bpx-player-ctrl-time-label"]')start_time = detection_time1[0].textsleep(5)# 时间戳检测是否在播放detection_time2 = driver.find_elements_by_xpath('//*[@class="bpx-player-control-bottom-left"]//div[@class="bpx-player-ctrl-time-label"]')end_time = detection_time2[0].textif start_time == end_time or check_btn:print("点击播放(暂停)按钮")paus_btn[0].click()except Exception as e:print(f"点击播放(暂停)出错{e}")#发送弹幕
def video_sms(sms_body="不错"):if isLogin:try:sms_input_edit = driver.find_element_by_xpath("//input[@class='bpx-player-dm-input']")sms_input_edit.send_keys(sms_body)# 模拟发送Enter键sms_input_edit.send_keys(Keys.ENTER)except Exception as e:print(f"发弹幕出错{e}")print(f"发送弹幕:{sms_body}")#点赞
def video_love():if isLogin:print("点赞")try:sms_input_edit = driver.find_elements_by_xpath("//div[@class='toolbar-left-item-wrap']//div[@class='video-like video-toolbar-left-item']")if not sms_input_edit:print("已经点赞")returnsms_input_edit[0].click()except Exception as e:print(f"点赞出错{e}")#收藏
def video_collect():if isLogin:print("收藏")try:colle_btn = driver.find_elements_by_xpath("//div[@class='toolbar-left-item-wrap']//div[@class='video-fav video-toolbar-left-item']")if not colle_btn:print("已经收藏")returncolle_btn[0].click()sleep(2)list_coll = driver.find_elements_by_xpath("//div[@class='group-list']//ul/li/label")random_element = random.choice(list_coll) # 随机收藏# 滚动到指定元素处driver.execute_script("arguments[0].scrollIntoView(true);", random_element)sleep(2)random_element.click() # 随机收藏一个sleep(2)driver.find_element_by_xpath("//div/button[@class='btn submit-move']").click() # 确认收藏except Exception as e:print(f"收藏出错{e}")# 等待元素出现
def wait_for_element(driver, selector, timeout=60 * 5):try:element = WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.XPATH, selector)))return elementexcept Exception:print("元素未出现")return None#头像元素初始化
selem = "//div[@class='bili-header fixed-header']//*[contains(@class, 'header-avatar-wrap--container mini-avatar--init')]"if __name__ == "__main__":start_selenium() # 开启浏览器找到视频播放is_login() # 检测是否出现登录弹窗# 等待元素出现element = wait_for_element(driver, selem)if element:print("检测到已经登录")# 暂停和播放视频for _ in range(2):video_pause_and_play()sleep(3)driver.refresh()# 发送弹幕sms_list = ["感觉不错,收藏了", "666,这么强", "自动化还得看airtest", "干货呀", "麦克阿瑟直呼内行"]for item in sms_list:wait_time = random.randint(5, 10) # 随机生成等待时间,单位为秒time.sleep(wait_time) # 等待随机的时间video_sms(item) # 评论# 点赞和收藏视频for action in [video_love, video_collect]:action()sleep(3)else:print("登录超时")
3.2 重要知识点
1)切换新页面并打开新的标签页
driver.switch_to_new_tab()
**2)将随机的元素 random_element对象的“顶端”移动到与当前窗口的“顶部”**对齐。
driver.execute_script("arguments[0].scrollIntoView(true);", random_element)
3) 从非空序列中随机选取一个数据并返回,该序列可以是list、tuple、str、set**。**
random.choice()
4) 通过实例化threading.Thread类创建线程,target:在线程中调用的对象,可以为函数或者方法;args为target对象的参数。
start():开启线程,如果线程是通过继承threading.Thread子类的方法定义的,则调用该类中的run()方法;start()只能调用一次,否则报RuntimeError。
threading.Thread(target=is_no_login, args=("args",))
thread.start()
5) 使用expected_conditions模块(在使用时通常重命名为EC模块)去判断特定元素是否存在于页面DOM树中,如果是,则返回该元素(单个元素),否则就报错。
EC.presence_of_element_located((By.XPATH, selector))
4. 注意事项与小结
4.1 相关教程
- 如何使用Airtest-selenium进行web端的页面元素交互
- 如何设置chromedriver以及一些常见的web脚本问题
- 为什么AirtestIDE无法检索web控件?
4.2 课程小结
在本周的课程中,我们介绍了如何使用Airtest-selenium进行自动化刷B站视频的操作流程,也分享了Airtest-selenium比较常见的用法。但是,请大家注意,我们的分享仅供学习参考哦!我们分享的代码并不是永远适用的,因为网页的页面元素可能会不断更新。
同时,我们也非常欢迎同学们能够提供自己常用场景的代码,我们会积极分享相关的使用技巧。让我们一起努力,共同进步~
相关文章:
Airtest-Selenium实操小课②:刷B站视频
1. 前言 上一课我们讲到用Airtest-Selenium爬取网站上我们需要的信息数据,还没看的同学可以戳这里看看~ 那么今天的推文,我们就来说说看,怎么实现看b站、刷b站的日常操作,包括点击暂停,发弹幕,点赞&#…...

Linux chmod命令详解
Linux chmod(英文全拼:change mode)命令是控制用户对文件的权限的命令 Linux/Unix 的文件调用权限分为三级 : 文件所有者(Owner)、用户组(Group)、其它用户(Other Users)…...

求幸存数之和 - 华为OD统一考试
OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 给一个正整数列nums,一个跳数jump,及幸存数量left。运算过程为:从索引为0的位置开始向后跳,中间跳过 J 个数字,命中索引为 J+1 的数字,该数被敲出,并从该点起跳,以此类推,直到幸存left个数为止。…...

【QML COOK】- 008-自定义属性
前面介绍了用C定义QML类型,通常在使用Qt Quick开发项目时,C定义后端数据类型,前端则完全使用QML实现。而QML类型或Qt Quick中的类型时不免需要为对象增加一些属性,本篇就来介绍如何自定义属性。 1. 创建项目,并编辑Ma…...

前端页面优化做的工作
1.分析模块占用空间 new (require(webpack-bundle-analyzer).BundleAnalyzerPlugin)() 2.使用谷歌浏览器中的layers,看下有没有影响性能的模块,或者应该销毁没销毁的 3.由于我们页面中含有很大的序列帧动画,所以会导致页面性能低࿰…...

Spark六:Spark 底层执行原理SparkContext、DAG、TaskScheduler
Spark底层执行原理 学习Spark运行流程 学习链接:https://mp.weixin.qq.com/s/caCk3mM5iXy0FaXCLkDwYQ 一、Spark运行流程 流程: SparkContext向管理器注册并向资源管理器申请运行Executor资源管理器分配Executor,然后资源管理器启动Execut…...
关于鸿蒙的笔记整理
提示:有使用过 vue 或 react 的小伙伴更容易理解 知识点强调: ArkTS所有内容都不支持深层数据更新 UI渲染 文章目录 一、关于样式1 . 默认单位 vp2 . 写公共样式 二 、 加载图片三 、 自定义构建函数 Builder四、构建函数-BuilderParam 传递UI五 、 父子…...

【漏洞复现】先锋WEB燃气收费系统文件上传漏洞 1day
漏洞描述 /AjaxService/Upload.aspx 存在任意文件上传漏洞 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作…...

MYSQL篇--锁机制高频面试题
Mysql锁机制 1对mysql的锁有了解吗? 首先我们要知道,mysql的锁 其实是为了解决在并发事务时所导致的数据不一致问题的一种处理机制,也就是说 在事务的隔离级别实现中,就需要利用锁来解决幻读问题 然后我们可以聊到锁的分类 按锁…...

创建一个郭德纲相声GPTs
前言 在这篇文章中,我将分享如何利用ChatGPT 4.0辅助论文写作的技巧,并根据网上的资料和最新的研究补充更多好用的咒语技巧。 GPT4的官方售价是每月20美元,很多人并不是天天用GPT,只是偶尔用一下。 如果调用官方的GPT4接口&…...

靶机实战(10):OSCP备考之VulnHub Tre 1
靶机官网:Tre: 1[1] 实战思路: 一、主机发现二、端口发现(服务、组件、版本)三、漏洞发现(获取权限) 8082端口/HTTP服务 组件漏洞URL漏洞(目录、文件)80端口/HTTP服务 组件漏洞URL漏…...

在windows11系统上利用docker搭建linux记录
我的windows11系统上,之前已经安装好了window版本的docker,没有安装的小伙伴需要去安装一下。 下面直接记录安装linux的步骤: 一、创建linux容器 1、拉取镜像 docker pull ubuntu 2、查看镜像 docker images 3、创建容器 docker run --…...
swift对接环信sdk
准备 熟练objective-c语言 有一台mac电脑,并安装了xcode 和 cocoapods 内容篇幅较长,需要内心平和耐心看下去,务必戒躁. 学习目的 手把手教大家如何在iOS应用中集成环信IM 明确表示,内容一定全面,没有任何丢失,只要沉得住气,耐得下心,3小时即可搞定. 若经常阅读文档以及语…...

单片机中的PWM(脉宽调制)的工作原理以及它在电机控制中的应用。
目录 工作原理 在电机控制中的应用 脉宽调制(PWM)是一种在单片机中常用的控制技术,它通过调整信号的脉冲宽度来控制输出信号的平均电平。PWM常用于模拟输出一个可调电平的数字信号,用于控制电机速度、亮度、电压等。 工作原理 …...

css 怎么绘制一个带圆角的渐变色的边框
1,可以写两个样式最外面的div设置一个渐变的背景色。里面的元素使用纯色。但是宽高要比外面元素的小。可以利用里面的元素设置padding这样挡住部分渐变色。漏出来的渐变色就像边框一样。 <div class"cover-wrapper"> <div class"item-cover…...
Kotlin DSL C++项目引入OpenCV异常处理
现象 kotlin DSL(build.rgadle.kts)项目引入openCV sdk 编译提示Plugin [id: com.android.application, version: 8.2.1...错误 Plugin [id: com.android.application, version: 8.2.1, apply: false] was not found in any of the following sources:* Try: > Run with -…...
【微服务】 Spring cold、Kubernetes、Service mesh
目录 Spring Cloud # 什么是微服务?谈谈你对微服务的理解? # 什么是Spring Cloud? # springcloud中的组件有那些? # 具体说说SpringCloud主要项目? # Spring Cloud 和dubbo区别? # 服务注册和发现是什么意思?S…...

【scala】编译build报错 “xxx is not an enclosing class“
private[sources] val creationTimeMs: Long {val session SparkSession.getActiveSession.orElse(SparkSession.getDefaultSession)require(session.isDefined)private[xxx]是访问权限控制在xxxx包的意思。 解决办法: 把[sources]删掉,或者改成和包名…...

vue3+ts+vite项目从0 搭建,配置安装router/pinia/element-plus/scss等
一、安装vite环境 官网:https://cn.vitejs.dev/guide/why.html npm init vite1.选择vue 2.选择typescipt 3.创建成功 默认项目结构如下 4.安装项目依赖 npm install 5.启动项目 npm run dev二。安装配置scss 1.运行安装scss npm install -D sass sass-loa…...
华为OD机试 - 矩阵匹配(Java JS Python C)
题目描述 从一个 N * M(N ≤ M)的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求:1 ≤ K ≤ N ≤ M ≤ 150 输入格式: N M K N*M矩阵 输出描述 N*M 的矩阵中可以选出 M! / N! 种组合数…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...