如何用Selenium+Chrome模擬登陸並獲取Cookie值

我們在Python做網絡爬蟲的時候,對於一些頁面信息的爬取,很多信息網頁會提示說需要登陸才能查看更多信息,這個時候我們就逃不開需要模擬登陸了,這裏我們就可以利用上自動化測試神奇Selenium來模擬我們的鼠標、鍵盤進行登陸。這裏我用我最近剛剛完成的一個網頁來做講解,也算是一種記錄了。
本篇分兩部分講,第一部分介紹cookie值,第二部分介紹Selenium的相關方法以及操作

第一部分:Cookie值

1.什麼是Cookie值:

當我們對網頁發送請求時,對於那些需要瀏覽器需要登陸才能返回的信息,服務器如何去區分瀏覽器是否包登陸信息,然後分別返回對應的內容呢?這裏就是我們要介紹到的Cookie值用處了。
cookie是由服務器發送到瀏覽器的變量。cookie 通常是服務器嵌入到用戶計算機中的小文本文件。每當計算機通過瀏覽器請求一個頁面,就會發送這個cookie。

2.Cookie值有什麼用

Cookie值被設計用來保存一些站點的用戶數據,這樣能夠讓服務器爲這樣的用戶定製內容,後者頁面代碼能夠獲取到Cookie值然後發送給服務器。

下面以一個例子來說明Cookie值的用處
當我們希望對需要登陸才能訪問的信息發送請求時,服務器如何知道瀏覽器發送的請求是否包含登陸信息,這裏就需要利用到Cookie值,服務器通過檢索瀏覽器發送來的Cookie值來判斷,然後返回不同的內容。如果用瀏覽器的概念比較不好理解,那麼接下來就用一個簡單的代碼來發送請求,並獲取Cookie值,然後利用兩種Cookie值(登陸後和沒有包含登陸信息的Cookie值),來說明Cookie的用處

*我們知道想要獲取瀏覽器的Cookie值,Python有一個包叫做http.cookiejar包,這個包可以用來獲取瀏覽器的Cookie值,下面我直接對一個網頁發送請求,然後獲取一個網頁的Cookie值,結果如下:

name: PHPSESSID -value: kn1n2iq9usj77davkmec4vi7a4
name: acw_tc -value: AQAAAKEGMFaK7wMA/X/oKsHdye4JAEWw

經過測試,利用這些Cookie值並不能返回給我登錄後才能返回的信息。而且,在網頁上利用瀏覽器的開發者選項(F12)查看Cookie值會發現,其他鍵值對都沒有返回。
接下來是我利用Selenium模擬登錄網頁後獲取的Cookie值:

['acw_tc=AQAAAF+W1SvfaAIA/X/oKtCgzhD+AeBV', 
'_umdata=ED82BDCEC1AA6EB98EEDF380D0DDDD1DB0686BDCF0848311659A6108D5A46E3BE2754ADA65ACE593CD43AD3E795C914CBC0E61E5F537EFB039856DF64AF08E44',
 'PHPSESSID=d1srrbvlt75qq5p46jeh8g7m23', 'hasShow=1', 
'CNZZDATA1254842228=260499800-1518055240-%7C1518055240', 
'_uab_collina=151805999511010799873236', 
'zg_did=%7B%22did%22%3A%20%22161736d30a4cb-0c0aa0eefb862a-3b60490d-144000-161736d30a552e%22%7D', 
'zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f=%7B%22sid%22%3A%201518059991209%2C%22updated%22%3A%201518060013600%2C%22info%22%3A%201518059991270%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%228731ad9f297a7dbbcff0814343e06ea3%22%7D']

這裏可以看到登錄後的Cookie值返回了所有鍵值對,經過測試,通過發送這裏的Cookie值請求網頁,可以實現模擬登錄的效果。
*第二種我們可以從模擬瀏覽器的方法的入手,理解Cookie值的用處。我們知道用Python的Requests模塊對網頁發送請求可以用requests.get(url, params, headers, proxies, timeout .....)當我們需要模擬瀏覽器登錄的時候可以將header屬性賦使用的瀏覽器User-Agent,例如:

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) \
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

或者更復雜一點的,把Request Headers下的所有屬性都加上,例如:

request_headers = {
    'Accept':'text/html, */*; q=0.01',
    'Accept-Encoding':'gzip, deflate',
    'Accept-Language':'zh-CN,zh;q=0.9',
    'Connection':'keep-alive',
    'Cookie':'acw_tc=AQAAAAFSbEV6igQAU3joKmb1pHb7Amkd;_umdata=2BA477700510A7DF4059C61C78E8395939FAD577E94352328D751D6CD84A71DC483C7165B9EADDACCD43AD3E795C914C9155FE5460049F4934F91027D34B6E6F;PHPSESSID=lrcjhpkrjtbffirbtch8hrh9g2;hasShow=1;UM_distinctid=1616afff050228-00a2c5f077a432-3b60490d-144000-1616afff052387;CNZZDATA1254842228=1796631317-1517916172-%7C1517916172;_uab_collina=151791861517128939720221;zg_did=%7B%22did%22%3A%20%221616afff15d69f-06e4c98572085c-3b60490d-144000-1616afff15e48b%22%7D;zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f=%7B%22sid%22%3A%201517918613857%2C%22updated%22%3A%201517918631284%2C%22info%22%3A%201517918613860%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%228731ad9f297a7dbbcff0814343e06ea3%22%7D;',
    'Host':'www.qichacha.com',
    'Referer':'http://www.qichacha.com/firm_06396efe66551d4ac07ee8cb41b0e325.html',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36',
    'X-Requested-With':'XMLHttpRequest'
    }

把所有鍵值對用字典的形式保存下來,然後賦給headers屬性。

那麼這兩種方法有什麼不同用處和區別呢?當時我們在做淘寶評論爬蟲的時候也遇到過需要登陸的問題,當時發現只用User-Agent沒有用,仍然需要登錄,於是我就在PC瀏覽器端手動登錄,然後想着希望程序能模擬瀏覽器,就把Request Headers下的屬性值像上面那樣構造成字典,賦給header屬性,結果真的可以了。當時我還以爲程序真的能檢測到我在PC端瀏覽器的操作這麼神奇。。。當時沒有管那麼多,就一直這樣做了。

但是這次在做這次的爬蟲時,我才體會到其實程序的確’檢測’了我在PC端瀏覽器的操作,只是這種方式是利用Cookie值。當時我直接複製了瀏覽器下的Request Headers下的內容,那麼這裏的Cookie值就對應了我PC端瀏覽器訪問網頁後,保存在本地的小文件裏的一些用戶信息(對應前面說的什麼是Cookie值)。

當我通過瀏覽器訪問站點時,瀏覽器會在個人電腦上行查找和該站點對應的Cookie文件,如果發現了就會把裏面的鍵值對內容全部發送給Web服務器,如果沒找到則不發送。所以也就是說當我在程序中利用PC瀏覽器端保存的Cookie值進行訪問時,這個Cookie值其實記錄和保存了的是我在瀏覽器端登錄後保存在本地文件的Cookie值,每次我在PC端瀏覽器登錄後再請求站點時,瀏覽器就會在我的電腦上找到該站點登錄後對應的Cookie值。所以如果我想在程序中利用該Cookie值模擬登錄的效果,那麼就必須在瀏覽器上登錄後,對應站點的Web服務器才能獲取到該Cookie值,並告知該Cookie包含登錄信息,有效。否則,程序只單獨利用該Cookie值,不能取得登錄效果。所以這也就解釋了,爲什麼當時我會以爲程序’神奇‘的真的模擬了我的PC端瀏覽器。

而且通過實驗也可以發現,對於大部分的網頁,Request Headers下的屬性,只有Cookie屬性和User-Agent是常常利用比較多的。所以說了那麼多,其實簡而言之,就是希望大家能理解,對於那些站點需要登錄才能獲取的信息,我們需要構建Cookie值,並攜帶登錄後的Cookie值發送請求,這樣才能獲得對應信息。

那麼如何才能獲得登錄後的Cookie值呢?而且要知道,對於不同的電腦和不同的瀏覽器,Cookie值都是不相同的,如果你想你的攜帶了Cookie值的爬蟲程序可以在不同的電腦上都能運行,那麼就不能像上面那樣,只是把你自己瀏覽器下的Cookie值複製過來,然後攜帶發送請求,因爲這樣你的程序換一臺電腦之後,就無法實現模擬登錄的效果了。所以,如果希望我們的程序繁華能力更強,那麼我們就一定要讓我們的程序能自己輸入賬號密碼進行登錄,然後自動獲取Cookie值,並讓程序攜帶Cookie值發送請求。

利用Selenium模擬登錄

如何你百度如何模擬瀏覽器登錄,那麼你肯定能看到這個模塊。Selenium是一個網頁自動化測試的神器,它可以通過簡單的函數,就能模擬你的鼠標、鍵盤等的操作,例如輸入賬號密碼,點擊、拖拽等等功能,可謂是簡單高效。
具體相關的API我就不過多介紹了,這裏有篇博客介紹的還是比較詳細的,以及Selenium的官方中文翻譯文檔
python中seleniumAPI的用法
Selenium with Python中文翻譯文檔

這裏我就主要介紹如何來模擬登錄,如何處理登錄時需要拖動滑塊進行驗證的情況。
這裏寫圖片描述

輸入賬號密碼都比較簡單了,拖動滑塊的話,就需要用到move_by_offset(xoffset, yoffset)這個函數了,參數故名思意就是橫向和縱向所要移動的距離。那拖動滑塊自然就只需要設定x的值。

這個值要去哪兒獲取呢?這時我們可以打開瀏覽器的開發者選項(F12),然後找到滑塊對應的大小
這裏寫圖片描述
當然,有點數學知識的都可能感覺到不對呀,那滑塊也是有大小的呀,真正的拖動距離應該是348-滑塊的長才對。所以我們可以用同樣的方法對應到滑塊的大小,然後相減。(當然其實我們拖多了也是可以的,例如直接設置成400)。

就這樣就OK了,就是這麼簡單神奇,當然網頁也並不會讓你這麼簡單就破解。我覺得Selenium比較不好的就是,這個函數不能設定拖動速度,每次拖動完可能是因爲拖動速度太快,總是會需要再輸入驗證碼(當然可能某些網站不需要,那就最好了)。那就再需要找到對應的驗證碼的png圖片然後識別,分割之類的了,這裏就沒有辦法再討論了,(我也不會。。)

所以,以後當我們遇到需要登錄的情況時,就可以利用Selenium來實現了~Selenium支持多款瀏覽器,這裏我用的是Selenium+Chrome,所以就需要下載一個chromedriver.exe的驅動程序。
這裏貼出chromedriver下載的官方網址,可自行下載
chromedriver

代碼如下:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
import re

acw_tc_re = re.compile('acw_tc')
phpsessid_re = re.compile('PHPSESSID')
acw_php_re = re.compile('acw_tc|PHPSESSID')

path = 'E:\Anaconda3_4.4.0_Windows_x86_64\chromedriver_win32\chromedriver.exe'

#url = 'http://www.qichacha.com/firm_06396efe66551d4ac07ee8cb41b0e325.html'
login_url = 'http://www.qichacha.com/user_login'
url2 = 'http://www.qichacha.com/'

class Get_Cookies(object):
    def __init__(self, path, url):
        self.path = path      #chromedriver驅動程序的絕對路徑地址
        self.url = url        #訪問站點

    def extract_cookie(self):

        cookies = ''

        driver = webdriver.Chrome(self.path)      #定義對象
        driver.get(self.url)       #請求網頁

        denglu = driver.find_element_by_link_text('登錄')

        action = ActionChains(driver)       #定義需要鼠標鍵盤類動作

        denglu.click()        #模擬鼠標點擊右上角的登錄

        curpage_url = driver.current_url      #返回當前界面的url
        print(curpage_url)

        while(curpage_url == login_url):      #進行循環判斷,直到當前界面發生切換,才說明登錄成功
            username = '****'        #賬號
            password = '*******'     #密碼

            nameNormal =driver.find_element_by_id('nameNormal')    #找到輸入賬號的文本框
            pwdNormal = driver.find_element_by_id('pwdNormal')     #找到輸入密碼的文本框

            nameNormal.clear()
            nameNormal.send_keys(username)    #寫入賬號
            time.sleep(3)
            pwdNormal.clear()
            pwdNormal.send_keys(password)     #寫入密碼

            while True:       #防止因爲網絡不穩定,導致滑塊沒有加載出來,就會報錯。(根據自己的實際情況)
                try:
                    huakuai = driver.find_element_by_id('nc_1_n1z')    #根據id值找到滑塊的位置

                    action.click_and_hold(huakuai)      #按住滑塊
                    action.move_by_offset(100,0).perform()    #先拖動滑塊100
                    time.sleep(1)
                    action.move_by_offset(100,0).perform()
                    time.sleep(1)
                    action.move_by_offset(108,0).perform()
                    break
                except:
                    pass

            tongguo_xpath2 = '//*[@id="nc_1__scale_text"]/span[@data-nc-lang="_yesTEXT"]'
            login_in_xpath = '//*[@id="user_login_normal"]/button'

            while True:
                try:
                    text = driver.find_element_by_xpath(tongguo_xpath2)   #直到拖動滑塊驗證完成後,條形框上顯示‘驗證通過’
                    break
                except:
                    pass

            login_in = driver.find_element_by_xpath(login_in_xpath)
            login_in.click()

            time.sleep(3)

            curpage_url = driver.current_url

        #get the session cookie
        cookie = [item['name'] + '=' + item['value'] for item in driver.get_cookies()]
        print(cookie)

        for value in cookie:
            #m = acw_php_re.search(value)
            #if m:
                #cookies += value + ';'
            cookies += value + ';'

        print(cookies)
        return cookies


#cookie = Get_Cookies(path, url2)
#cookie.extract_cookie()

最後提供幾個類似的用Selenium攻破驗證碼的博客
python2.7+selenium2實現淘寶滑塊自動認證

滑塊驗證碼(滑動驗證碼)相比圖形驗證碼,破解難度如何?
Python爬蟲常用之登錄(二) 瀏覽器模擬登錄
使用Selenium模擬瀏覽器,實現自動爬取數據

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