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))
总结:

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

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

软件测试面试文档

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

相关推荐
HsuHeinrich2 分钟前
流程图(二)利用python绘制网络图
python·数据可视化
爱学习的Allan12 分钟前
使用 pyreqs 快速创建 requirements.txt & PyCharm 中 UnicodeDecodeError 问题
ide·python·pycharm·pip
HackKong33 分钟前
高校网络安全_网络安全之道
java·网络·c++·python·学习·web安全·黑客技术
yangjiwei02071 小时前
数据结构-排序
数据结构·python
秋天下着雨1 小时前
apifox调用jar程序
java·python·jar
bs_1011 小时前
【保姆式】python调用api通过机器人发送文件到飞书指定群聊
python·机器人·飞书
Redamancy_Xun2 小时前
软件老化分析
python·程序人生·安全威胁分析·可信计算技术·安全架构
geovindu2 小时前
python: Oracle Stored Procedure query table
数据库·python·mysql·postgresql·oracle·sqlserver·mssql
NiNg_1_2342 小时前
Python中SKlearn的K-means使用详解
python·kmeans·sklearn
葡萄架子2 小时前
Python中的logger作用(from loguru import logger)
java·前端·python