Python爬蟲實戰——12306火車購票(附實例)

春運到了,你還在手動買火車票嗎?

1、什麼是selenium

在想要看懂代碼之前一定要問問自己,啥是個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的核心Selenium Core基於JsUnit,完全由JavaScript編寫,因此可以用於任何支持JavaScript的瀏覽器上。selenium可以模擬真實瀏覽器,自動化測試工具,支持多種瀏覽器,爬蟲中主要用來解決JavaScript渲染問題。

2、selenium的常見庫及其使用

在這裏插入圖片描述

我們可以觀察到,selenium支持多種瀏覽器,本文中我將主要使用webdriver.Chrome進行自動化測試

小案例

這裏構造一個簡單的小案例方便你更好的瞭解它

from selenium import webdriver  # 導入庫

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

注: 如果想要進行一點完善的話可以添加time模塊

查找

selenium最方便的地方在於,你可以通過多種方法來定位頁面信息,這裏我列舉一些常用方法:

find_element_by_name
find_element_by_id
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

至於每一種的效果如何或者是使用情況,請依照個人需求靈活選擇。

獲取文本值

browser.get("http://www.zhihu.com/explore")
logo = browser.find_element_by_css_selector('.zu-top-link-logo')
print(logo)
print(logo.text)

運行代碼我們可以得到標籤下的文本值:

<selenium.webdriver.remote.webelement.WebElement (session="ce8814d69f8e1291c88ce6f76b6050a2", element="0.9868611170776878-1")>
知乎

模擬點擊

這裏內容比較多,我們可以通過selenium下的 ActionChains 類,由於篇幅過長這裏只截取部分

class ActionChains(object):
    """
    ActionChains are a way to automate low level interactions such as
    mouse movements, mouse button actions, key press, and context menu interactions.
    This is useful for doing more complex actions like hover over and drag and drop.
 
    Generate user actions.
       When you call methods for actions on the ActionChains object,
       the actions are stored in a queue in the ActionChains object.
       When you call perform(), the events are fired in the order they
       are queued up.
 
    ActionChains can be used in a chain pattern::
 
        menu = driver.find_element_by_css_selector(".nav")
        hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
 
        ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
 
    Or actions can be queued up one by one, then performed.::
 
        menu = driver.find_element_by_css_selector(".nav")
        hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
 
        actions = ActionChains(driver)
        actions.move_to_element(menu)
        actions.click(hidden_submenu)
        actions.perform()
 
    Either way, the actions are performed in the order they are called, one after
    another.
    """
 
    def __init__(self, driver):
        """
        Creates a new ActionChains.
 
        :Args:
         - driver: The WebDriver instance which performs user actions.
        """
        self._driver = driver
        self._actions = []
        if self._driver.w3c:
            self.w3c_actions = ActionBuilder(driver)
 
    def perform(self):
        """
        Performs all stored actions.
        """
        if self._driver.w3c:
            self.w3c_actions.perform()
        else:
            for action in self._actions:
                action()
 
    def reset_actions(self):
        """
            Clears actions that are already stored on the remote end.
        """
        if self._driver.w3c:
            self._driver.execute(Command.W3C_CLEAR_ACTIONS)
        else:
            self._actions = []
            
      ....

3、操作實戰

在實現登錄過程中,首先需要逐步解析頁面,通過xpath工具、頁面審查等方式定位到相應的標籤下,通過模擬點擊、輸入文本等方式進行信息輸入、表單選擇等過程。

在這裏插入圖片描述

例如我們從上圖中,定位到了下拉表單中的始發地/目的地信息,只有這樣我們纔可以對其中的數據進行修改,直到達到我們所預期的效果

測試登錄過程

美中不足的是,12306特有的圖片驗證碼還未找到合適的方法實現自動破解,只能通過人工識別完成這一步驟。

在這裏插入圖片描述

至此我們的測試就已經結束,可以看到效果還是很不錯的,避免了反覆通過輸入密碼、選擇站點等操作,極大程度的減少了不必要的操作!只需將常用的站點xpath路徑保存好即可。

4、代碼上場

下面附贈本次實驗中的部分代碼,希望能給各位讀者一些幫助!

from selenium import webdriver
import time


def main():
    login_text()
    search_ticket()
    book_ticket()


def login_text():
    d.get(url)
    d.implicitly_wait(30)
    # 登陸賬號
    username_ele = d.find_element_by_id('username')
    username_ele.clear()
    username_ele.send_keys(username)
    # 登陸密碼
    pwd_ele = d.find_element_by_id('password')
    pwd_ele.clear()
    pwd_ele.send_keys(pwd)

    while True:  # 手動進行圖片驗證,並登錄
        curpage_url = d.current_url
        if curpage_url != url:
            if curpage_url[:-1] != url:
                print('.......登陸成功........')
                break
        else:
            time.sleep(3)
            print('------細心點老鐵!慢慢來!-----')


def search_ticket():
    time.sleep(2)
    d.find_element_by_link_text('車票').click()
    d.find_element_by_link_text('單程').click()
    time.sleep(3)

    # 輸入出發地
    d.add_cookie({"name": "_jc_save_fromStation", "value": '%u547C%u548C%u6D69%u7279%2CHHC'})  # 鄂爾多斯

    # 選擇目的地
    d.add_cookie({"name": "_jc_save_toStation", "value": '%u9102%u5C14%u591A%u65AF%2CEEC'})  # 呼和浩特

    # 選擇出發日期
    d.add_cookie({"name": "_jc_save_fromDate", "value": '2019-11-06'})
    d.refresh()


def book_ticket():
    query_time = 0
    time_begin = time.time()
    # 循環查詢
    while True:
        time.sleep(1)
        search_btn = d.find_element_by_link_text('查詢')
        search_btn.click()

        # 掃描查詢結果
        try:
            d.implicitly_wait(3)
            # 鄂爾多斯到呼和浩特的D6963的PATH:(//*[@id="ZE_33000D696300"])
            ticket_ele = d.find_element_by_xpath('//*[@id="ZE_33000D696300"]')  # 所搶車次對應的座位等級的xpath,這裏是二等座
            ticket_info = ticket_ele.text
        except:
            search_btn.click()
            d.implicitly_wait(3)
            ticket_ele = d.find_element_by_xpath('//*[@id="ZE_33000D696300"]')
            ticket_info = ticket_ele.text
            print('可能您的xpath選擇錯誤')

        if ticket_info == '無' or ticket_info == '*':
            query_time += 1
            cur_time = time.time()
            print('第%d次查詢,用時%s秒' % (query_time, cur_time - time_begin))
        else:
            d.find_element_by_xpath('//*[@id="ticket_33000D696300"]/td[13]/a').click()
            break

    cust_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    while True:
        if (d.current_url == cust_url):
            print('頁面跳至選擇乘客信息 成功')
            break
        else:
            time.sleep(1)
            print('等待頁面跳轉')

    while True:
        try:
            time.sleep(2)
            d.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()  # _0是聯繫人列表裏的第一個 ,依此類推
            break
        except:
            print('等待常用聯繫人列表')

    # 提交訂單
    d.find_element_by_xpath('//*[@id="submitOrder_id"]').click()

    # 確認訂票信息
    while True:
        try:
            d.switch_to.frame(d.find_element_by_xpath('/html/body/iframe[2]'))

            d.find_element_by_xpath('//*[@id="qr_submit_id"]')
            print('pass')
        except:
            print('請手動選座和點擊確認信息')
            time.sleep(5)
            print('請完成購票,再見。')
            break


if __name__ == '__main__':
    d = webdriver.Chrome()
    url = 'https://kyfw.12306.cn/otn/login/init'
    username = '這裏是你的用戶名'
    pwd = '這裏是你的密碼'
    main()

★希望各位讀者可以學到一些什麼,而不是單純地複製粘貼。Python的魅力在於,你可以使用它實現很多有趣而實用的案例,如有不足或錯誤之處還請各位讀者指出,謝謝!

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