用Python爬蟲實現自動簽到(一)—— selenium方式

用Python爬蟲實現自動簽到(一)—— selenium方式

tags: Python 爬蟲 自動簽到 selenium xpath


用爬蟲來實現自動簽到算是爬蟲裏一種比較簡單的應用,但不妨礙它很實用。總共會有兩篇博客分別用selenium的方式和requests請求的方式來分別實現,兩種方式各有優缺點,可根據實際情況酌情選擇。亦可作爲爬蟲練手。

有哪些應用場景

自動簽到的應用場景非常多,比如貼吧簽到、論壇簽到、網站打卡,甚至於我接下來會使用到的應用場景:健身房打卡。

由於疫情影響,我平常去的那家健身房停業了近3個月,於是推出了一個算是比較苛刻的補償措施或者說是活動,連續在網站打卡4個月可以額外贈送4個月時長。也算是過濾一下平常就不怎麼去健身的人吧,但是對大部分經常去的人就很不友好,本來就忙還得天天惦記着給他打卡。作爲一隻程序猿能讓這點小事難住了?

什麼是selenium

  • selenium 是一個用於Web應用程序測試的工具。Selenium測試直接運行在瀏覽器中,就像真正的用戶在操作一樣。支持的瀏覽器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。selenium 是一套完整的web應用程序測試系統,包含了測試的錄製(selenium IDE),編寫及運行(Selenium Remote Control)和測試的並行處理(Selenium Grid)。
  • selenium可以模擬真實瀏覽器,自動化測試工具,支持多種瀏覽器,爬蟲中主要用來解決JavaScript渲染問題。

什麼是selenium

selenium 是一個用於Web應用程序測試的工具。Selenium測試直接運行在瀏覽器中,就像真正的用戶在操作一樣。支持的瀏覽器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。selenium 是一套完整的web應用程序測試系統,包含了測試的錄製(selenium IDE),編寫及運行(Selenium Remote Control)和測試的並行處理(Selenium Grid)。
selenium可以模擬真實瀏覽器,自動化測試工具,支持多種瀏覽器,爬蟲中主要用來解決JavaScript渲染問題

簡單來說,selenium是一個可以讓你用代碼來模擬操作瀏覽器的工具。先附上一段代碼體驗一下

from selenium import webdriver#導入庫
browser = webdriver.Chrome()#聲明瀏覽器
url = 'https:www.baidu.com'
browser.get(url)#打開瀏覽器預設網址
print(browser.page_source)#打印網頁源代碼
browser.close()#關閉瀏覽器

上述代碼運行後,會自動打開Chrome瀏覽器,並登陸百度打印百度首頁的源代碼,然後關閉瀏覽器。是不是簡單明瞭。

安裝也非常簡單,跟安裝其他Python庫一樣

pip install selenium

網頁分析

寫爬蟲避不開的一步就是分析頁面,先附上要爬的網頁鏈接

這是一個手機端的web頁面,並沒有做針對電腦端的優化,這也是我首先會選擇用selenium實現的其中一個原因。

  1. 首先就是網頁登錄

兩個輸入框加一個按鈕總共三行代碼就能搞定

    # 這裏是找到輸入框,發送要輸入的用戶名和密碼,模擬登陸
    browser.find_element_by_xpath('//*[@id="login_box"]/ul/li[1]/div/input').send_keys(username)
    browser.find_element_by_xpath('//*[@id="login_box"]/ul/li[2]/div/input').send_keys(password)
    # 在輸入用戶名和密碼之後,點擊登陸按鈕
    browser.find_element_by_xpath('//*[@id="login_box"]/div[2]/button[1]').click()

我用的是xpath的方式定位頁面元素,除此之外selenium支持很多種方式定位元素,比如

    browser.find_element_by_class_name()
    browser.find_element_by_css_selector()
    browser.find_element_by_id()
    browser.find_element_by_name()

但不得不說,xpath+Chrome的組合實在是太香了。

再之後的操作就沒有什麼難度了,無非是繼續選擇元素,點擊,跳轉,點擊。需要注意的一點就是要合理的運用selenium的等待來使網頁的點擊和跳轉之間更加平滑。

selenium的三種等待方式

  1. 強制等待

    第一種是最簡單也是最粗暴的方式——強制等待。time.sleep(2) 不管瀏覽器有沒有加載完,都要等3秒。

    剛開始可以先用這種方式讓程序先跑起來,之後再優化。

  2. 隱性等待

    第二種方式叫隱性等待,implicitly_wait(xx)

    隱形等待是設置了一個最長等待時間,如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間截止,然後執行下一步。

    注意這裏有一個弊端,那就是程序會一直等待整個頁面加載完成,也就是一般情況下你看到瀏覽器標籤欄那個小圈不再轉,纔會執行下一步,但有時候頁面想要的元素早就在加載完成了,但是因爲個別js之類的東西特別慢,我仍得等到頁面全部完成才能執行下一步,我想等我要的元素出來之後就下一步怎麼辦?有辦法,這就要看selenium提供的另一種等待方式——顯性等待了。

  3. 顯性等待

    第三種辦法就是顯性等待,WebDriverWait,配合該類的until()和until_not()方法,就能夠根據判斷條件而進行靈活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果條件成立了,則執行下一步,否則繼續等待,直到超過設置的最長時間,然後拋出TimeoutException。

具體應用到代碼中如下:

from selenium.webdriver.support import expected_conditions as EC
locator = (By.XPATH, '//*[@id="login_box"]/ul/li[1]/div/input')
WebDriverWait(browser, 3, 0.3).until(EC.presence_of_element_located(locator))

WebDriverWait類長這樣:

class WebDriverWait(object):
    def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
        """Constructor, takes a WebDriver instance and timeout in seconds.

           :Args:
            - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
            - timeout - Number of seconds before timing out
            - poll_frequency - sleep interval between calls
              By default, it is 0.5 second.
            - ignored_exceptions - iterable structure of exception classes ignored during calls.
              By default, it contains NoSuchElementException only.

           Example:
            from selenium.webdriver.support.ui import WebDriverWait \n
            element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
            is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
                        until_not(lambda x: x.find_element_by_id("someId").is_displayed())
        """

until

  • method: 在等待期間,每隔一段時間調用這個傳入的方法,直到返回值不是False
  • message: 如果超時,拋出TimeoutException,將message傳入異常

until_not

  • 與until相反,until是當某元素出現或什麼條件成立則繼續執行,
  • until_not是當某元素消失或什麼條件不成立則繼續執行,參數也相同,不再贅述。

最終實現

知道了上面那些,就可以把我們的代碼優化一下,用顯性等待替換掉time模塊。最終代碼如下:

# username = "xxxxxx"
# password = "xxxxxx"
# 模擬瀏覽器打開網站
def AutoSign(username, password):
    chrome_options = Options()
    # 使用無界面瀏覽器
    chrome_options.add_argument('--headless')
    browser = webdriver.Chrome(options=chrome_options)
    browser.get(url)
    locator = (By.XPATH, '//*[@id="login_box"]/ul/li[1]/div/input')

    # 延時2秒,以便網頁加載所有元素,避免之後找不到對應的元素
    # time.sleep(2)
    WebDriverWait(browser, 3, 0.3).until(EC.presence_of_element_located(locator))

    # 這裏是找到輸入框,發送要輸入的用戶名和密碼,模擬登陸
    browser.find_element_by_xpath('//*[@id="login_box"]/ul/li[1]/div/input').send_keys(username)
    browser.find_element_by_xpath('//*[@id="login_box"]/ul/li[2]/div/input').send_keys(password)
    # 在輸入用戶名和密碼之後,點擊登陸按鈕
    browser.find_element_by_xpath('//*[@id="login_box"]/div[2]/button[1]').click()
    WebDriverWait(browser, 3, 0.3).until(EC.visibility_of_element_located((By.ID, 'name-a')))
    time.sleep(0.5)
    browser.execute_script("window.scrollTo(0,1000);")
    # 點擊登陸後的頁面中的簽到,跳轉到簽到頁面
    browser.find_element_by_xpath('//*[@id="member"]/div[6]/div/div[2]/div[1]/div/div/h3').click()
    # time.sleep(1)
    # browser.execute_script("window.scrollTo(0,1000);")
    # time.sleep(1)
    browser.find_element_by_xpath('//*[@id="member"]/div[6]/div/div[2]/div[2]/div/div/a[1]/div').click()
    # time.sleep(2)
    WebDriverWait(browser, 2, 0.3).until(
        EC.presence_of_element_located((By.XPATH, '//*[@id="sign"]/div[3]/div')))
    # 點擊簽到,實現功能
    browser.find_element_by_xpath('//*[@id="sign"]/div[3]/div').click()
    time.sleep(0.5)

    # 這個print其實沒什麼用,如果真的要測試腳本是否運行成功,可以用try來拋出異常
    print("簽到成功")

    # 腳本運行成功,退出瀏覽器
    browser.quit()

上面代碼中所有的conditionpoll_frequency需要根據實際網頁加載情況包括網絡狀況靈活調整,以便找到最優解。

其他相關資料已經同步到我的博客網站,歡迎訪問我的個人博客瞭解更多內容。

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