Airtest-Selenium实操小课

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文件就可以轻松登录啦~

先来看下我们整体的运行效果:

3.2 完整代码分享

这里也附上完整的示例代码给大家参考,有需要的同学可以自取学习哦:

  1. # -*- encoding=utf8 -*-

  2. from airtest.core.api import *

  3. # 引入selenium的webdriver模块

  4. from airtest_selenium.proxy import WebChrome

  5. from selenium.webdriver.common.keys import Keys

  6. from selenium.webdriver.common.by import By

  7. from selenium.webdriver.support.ui import WebDriverWait

  8. from selenium.webdriver.support import expected_conditions as EC

  9. import threading

  10. import time

  11. import random

  12. import json

  13. #保存以及调用cookie的线程

  14. class UtilFunc():

  15. def cookie_is_exist_(self, cook_name='_'): # 检查txt文件是否存在

  16. if os.path.exists(f'{cook_name}cookies.txt'):

  17. return True

  18. return False

  19. def cookie_save_(self, driver, cook_name='_'): #保存cookie到txt文件中以便下次读取

  20. # 获取当前页面的所有cookie

  21. cookies = driver.get_cookies()

  22. # 将cookie转换为JSON字符串

  23. cookies_json = json.dumps(cookies)

  24. # 保存cookie到txt文件

  25. with open(f'{cook_name}cookies.txt', 'w') as file:

  26. file.write(cookies_json)

  27. print(f"保存cookies:{cookies}")

  28. def cookie_set_(self, driver, cook_name='_'): #读取cookie文件并给当前网站设置已存cookie

  29. # 从txt文件读取JSON_cookie数据

  30. with open(f'{cook_name}cookies.txt', 'r', encoding='gbk') as file:

  31. json_data = file.read()

  32. # 将JSON数据转换为列表

  33. data_list = json.loads(json_data)

  34. for cookie in data_list:

  35. driver.add_cookie(cookie)

  36. print("设置cookie")

  37. # 创建一个实例,代码运行到这里,会打开一个chrome浏览器

  38. driver = WebChrome()

  39. isLogin = False #存储登录状态值,False为未登录,True为已登录

  40. #打开chrome浏览器并打开视频播放

  41. def start_selenium():

  42. driver.implicitly_wait(20)

  43. driver.get("https://www.baidu.com/")

  44. # 输入搜索关键词并提交搜索

  45. search_box = driver.find_element_by_name('wd')

  46. search_box.send_keys('哔哩哔哩')

  47. search_box.submit()

  48. try:

  49. # 查找搜索结果中文本为 "哔哩哔哩" 的元素并点击

  50. results = driver.find_elements_by_xpath('//div[@id="content_left"]//span[contains(text(), "哔哩哔哩")]')

  51. if results:

  52. results[0].click()

  53. print("点击了哔哩哔哩搜索结果")

  54. except Exception as e:

  55. element = driver.find_element_by_xpath(

  56. "//div[@id='content_left']/div[@id='1']/div[@class='c-container']/div[1]/h3[@class='c-title t t tts-title']/a")

  57. element.click()

  58. driver.switch_to_new_tab() # 切换界面

  59. util_cookie = UtilFunc()

  60. if util_cookie.cookie_is_exist_("Airtest酱登录"): # 存在cookie文件,设置cookie

  61. util_cookie.cookie_set_(driver, "Airtest酱登录")

  62. # 输入搜索关键词并提交搜索

  63. search_box = driver.find_element_by_class_name('nav-search-input')

  64. search_box.send_keys('Airtest酱')

  65. # 模拟发送Enter键

  66. search_box.send_keys(Keys.ENTER)

  67. sleep(5)

  68. driver.switch_to_new_tab() # 切换界面

  69. results_ = driver.find_elements_by_xpath(

  70. '//div[@class="bili-video-card__info--right"]//span[contains(text(),"Airtest酱")]')

  71. if results_:

  72. results_[0].click()

  73. driver.switch_to_new_tab() # 切换界面

  74. driver.refresh()

  75. sleep(2)

  76. video_ele = driver.find_element_by_xpath("//div[@title='14天Airtest自动化测试小白课程']")

  77. # 滚动到指定元素处

  78. driver.execute_script("arguments[0].scrollIntoView(true);", video_ele)

  79. sleep(5)

  80. video_ele.click()

  81. driver.switch_to_new_tab() # 切换界面

  82. # 获取所有视频

  83. video_list = driver.find_elements_by_xpath("//ul[@class='row video-list clearfix']//a[@class='title']")

  84. random_element = random.choice(video_list)

  85. random_element.click() # 随机播放一个

  86. driver.switch_to_new_tab() # 切换界面

  87. #登录

  88. def is_login():

  89. """线程检测登录弹窗"""

  90. def is_no_login(*args):

  91. global isLogin # 在线程内修改外部常量的值

  92. no_login_tip = True

  93. while True:

  94. element = driver.find_elements_by_css_selector('.bili-mini-content-wp')

  95. if len(element) > 0:

  96. if no_login_tip:

  97. print("未登录 请在五分钟内扫码")

  98. no_login_tip = False

  99. else:

  100. print("未检测到登录弹窗")

  101. check_login_ele = driver.find_elements_by_css_selector('.bpx-player-dm-wrap')

  102. if not check_login_ele:

  103. isLogin = True

  104. UtilFunc().cookie_save_(driver, "Airtest酱登录")

  105. print("保存cookie")

  106. break

  107. log_text_array = [element.text for element in check_login_ele] # 使用列表推导式简化代码

  108. if "请先登录或注册" in log_text_array:

  109. loginbtn = driver.find_elements_by_xpath(

  110. "//div[@class='bili-header fixed-header']//div[@class='header-login-entry']")

  111. if loginbtn:

  112. loginbtn[0].click()

  113. isLogin = False

  114. print("判断cookie文件是否存在,方便下次调用,设置后刷新页面")

  115. else:

  116. isLogin = True

  117. UtilFunc().cookie_save_(driver, "Airtest酱登录")

  118. print("保存cookie")

  119. break

  120. thread = threading.Thread(target=is_no_login, args=("args",))

  121. thread.start()

  122. #暂停播放

  123. def video_pause_and_play(check_btn=False):

  124. if isLogin:

  125. try:

  126. paus_btn = driver.find_elements_by_xpath(

  127. "//*[@id=\"bilibili-player\"]//div[@class='bpx-player-ctrl-btn bpx-player-ctrl-play']")

  128. if paus_btn[0]:

  129. detection_time1 = driver.find_elements_by_xpath(

  130. '//*[@class="bpx-player-control-bottom-left"]//div[@class="bpx-player-ctrl-time-label"]')

  131. start_time = detection_time1[0].text

  132. sleep(5)

  133. # 时间戳检测是否在播放

  134. detection_time2 = driver.find_elements_by_xpath(

  135. '//*[@class="bpx-player-control-bottom-left"]//div[@class="bpx-player-ctrl-time-label"]')

  136. end_time = detection_time2[0].text

  137. if start_time == end_time or check_btn:

  138. print("点击播放(暂停)按钮")

  139. paus_btn[0].click()

  140. except Exception as e:

  141. print(f"点击播放(暂停)出错{e}")

  142. #发送弹幕

  143. def video_sms(sms_body="不错"):

  144. if isLogin:

  145. try:

  146. sms_input_edit = driver.find_element_by_xpath("//input[@class='bpx-player-dm-input']")

  147. sms_input_edit.send_keys(sms_body)

  148. # 模拟发送Enter键

  149. sms_input_edit.send_keys(Keys.ENTER)

  150. except Exception as e:

  151. print(f"发弹幕出错{e}")

  152. print(f"发送弹幕:{sms_body}")

  153. #点赞

  154. def video_love():

  155. if isLogin:

  156. print("点赞")

  157. try:

  158. sms_input_edit = driver.find_elements_by_xpath(

  159. "//div[@class='toolbar-left-item-wrap']//div[@class='video-like video-toolbar-left-item']")

  160. if not sms_input_edit:

  161. print("已经点赞")

  162. return

  163. sms_input_edit[0].click()

  164. except Exception as e:

  165. print(f"点赞出错{e}")

  166. #收藏

  167. def video_collect():

  168. if isLogin:

  169. print("收藏")

  170. try:

  171. colle_btn = driver.find_elements_by_xpath(

  172. "//div[@class='toolbar-left-item-wrap']//div[@class='video-fav video-toolbar-left-item']")

  173. if not colle_btn:

  174. print("已经收藏")

  175. return

  176. colle_btn[0].click()

  177. sleep(2)

  178. list_coll = driver.find_elements_by_xpath("//div[@class='group-list']//ul/li/label")

  179. random_element = random.choice(list_coll) # 随机收藏

  180. # 滚动到指定元素处

  181. driver.execute_script("arguments[0].scrollIntoView(true);", random_element)

  182. sleep(2)

  183. random_element.click() # 随机收藏一个

  184. sleep(2)

  185. driver.find_element_by_xpath("//div/button[@class='btn submit-move']").click() # 确认收藏

  186. except Exception as e:

  187. print(f"收藏出错{e}")

  188. # 等待元素出现

  189. def wait_for_element(driver, selector, timeout=60 * 5):

  190. try:

  191. element = WebDriverWait(driver, timeout).until(

  192. EC.presence_of_element_located((By.XPATH, selector))

  193. )

  194. return element

  195. except Exception:

  196. print("元素未出现")

  197. return None

  198. #头像元素初始化

  199. selem = "//div[@class='bili-header fixed-header']//*[contains(@class, 'header-avatar-wrap--container mini-avatar--init')]"

  200. if __name__ == "__main__":

  201. start_selenium() # 开启浏览器找到视频播放

  202. is_login() # 检测是否出现登录弹窗

  203. # 等待元素出现

  204. element = wait_for_element(driver, selem)

  205. if element:

  206. print("检测到已经登录")

  207. # 暂停和播放视频

  208. for _ in range(2):

  209. video_pause_and_play()

  210. sleep(3)

  211. driver.refresh()

  212. # 发送弹幕

  213. sms_list = ["感觉不错,收藏了", "666,这么强", "自动化还得看airtest", "干货呀", "麦克阿瑟直呼内行"]

  214. for item in sms_list:

  215. wait_time = random.randint(5, 10) # 随机生成等待时间,单位为秒

  216. time.sleep(wait_time) # 等待随机的时间

  217. video_sms(item) # 评论

  218. # 点赞和收藏视频

  219. for action in [video_love, video_collect]:

  220. action()

  221. sleep(3)

  222. else:

  223. 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。

  1. threading.Thread(target=is_no_login, args=("args",))

  2. thread.start()

5) 使用expected_conditions模块(在使用时通常重命名为EC模块)去判断特定元素是否存在于页面DOM树中,如果是,则返回该元素(单个元素),否则就报错。

复制代码
EC.presence_of_element_located((By.XPATH, selector))
总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作

相关推荐
青 春 记 忆3 小时前
Dify Docker Compose 通用无损升级指南:从备份、双版本预演到切换与回滚
运维·人工智能·python·docker·容器
GlueNa2SiO33 小时前
03-Flask模板引擎Jinja2详解
笔记·python·flask
临沂GEO6 小时前
GEO搜索优化科普|正规地理位置流量运营入门指南
大数据·人工智能·python·流量运营
大模型码小白6 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
深蓝电商API7 小时前
常见反爬策略全解析
爬虫·反爬策略
荷蒲7 小时前
【小白量化Qbuddy】利用AI学习中文Python
人工智能·python·学习
数据狐(Datafox)9 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机9 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor69210 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy10 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源