Airtest-Selenium實操小課②:刷B站視頻

此文章來源於項目官方公衆號:“AirtestProject”
版權聲明:允許轉載,但轉載必須保留原鏈接;請勿用作商業或者非法用途

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 完整代碼分享

這裏也附上完整的示例代碼給大家參考,有需要的同學可以自取學習哦:

# -*- 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 True
        return False

    def cookie_save_(self, driver, cook_name='_'):     #保存cookie到txt文件中以便下次讀取
        # 獲取當前頁面的所有cookie
        cookies = 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文件,設置cookie
        util_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 = True
        while True:
            element = driver.find_elements_by_css_selector('.bili-mini-content-wp')
            if len(element) > 0:
                if no_login_tip:
                    print("未登錄 請在五分鐘內掃碼")
                    no_login_tip = False
            else:
                print("未檢測到登錄彈窗")
                check_login_ele = driver.find_elements_by_css_selector('.bpx-player-dm-wrap')
                if not check_login_ele:
                    isLogin = True
                    UtilFunc().cookie_save_(driver, "Airtest醬登錄")
                    print("保存cookie")
                    break
                log_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 = False
                    print("判斷cookie文件是否存在,方便下次調用,設置後刷新頁面")
                else:
                    isLogin = True
                    UtilFunc().cookie_save_(driver, "Airtest醬登錄")
                    print("保存cookie")
                    break

    thread = 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].text
                sleep(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].text
                if 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("已經點贊")
                return
            sms_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("已經收藏")
                return
            colle_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 element
    except 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 相關教程

4.2 課程小結

在本週的課程中,我們介紹瞭如何使用Airtest-selenium進行自動化刷B站視頻的操作流程,也分享了Airtest-selenium比較常見的用法。但是,請大家注意,我們的分享僅供學習參考哦!我們分享的代碼並不是永遠適用的,因爲網頁的頁面元素可能會不斷更新。

同時,我們也非常歡迎同學們能夠提供自己常用場景的代碼,我們會積極分享相關的使用技巧。讓我們一起努力,共同進步~


AirtestIDE下載:airtest.netease.com/
Airtest 教程官網:airtest.doc.io.netease.com/
搭建企業私有云服務:airlab.163.com/b2b

官方答疑 Q 羣:117973773

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章