使用Python自動登錄SSO爬取動態(tài)頁面

最近的項(xiàng)目在做一些數(shù)據(jù)方面的集成,五花八門的系統(tǒng)對應(yīng)的接口更是千奇百怪,數(shù)據(jù)集成的過程總結(jié)成八個字就是:逢山開路,遇水架橋。

恰好這兩天碰到一個問題,我們要集成的WEB系統(tǒng)沒有提供專門的數(shù)據(jù)集成接口,沒有API可以調(diào),數(shù)據(jù)庫更是不讓訪問,萬般無奈之下,我在想是否可以用python自動爬取頁面。web頁面有SSO,用的應(yīng)該是開源的CAS框架,并且后面的頁面全都是由動態(tài)JS、AJAX異步加載進(jìn)去的,這顯然不像普通的靜態(tài)頁面那樣直接用Scrapy上去就是一頓干,要完美的模擬登陸動作并且還要爬取后面的動態(tài)內(nèi)容,對頁面結(jié)構(gòu)和爬取內(nèi)容的分析是必不可少的。

工具

  • Chrome
    頁面分析工具非常簡單,只需要最新版本的Chrome瀏覽器即可
  • python3
  • requests

分析登錄頁面

打開登錄頁面,按F12打開Chrome自帶的分析工具,在Network選卡上可以看到當(dāng)前瀏覽器顯示頁面和提交登錄信息的詳情,如下圖


某網(wǎng)站登錄頁面

從截圖上可以看到,當(dāng)我們訪問app/這個url的日志,因?yàn)槲覀冞€沒有登錄過,SSO會把我們自動重定向到登錄頁面,所以http status是302重定向。

接下來我們在頁面上輸入賬號密碼,點(diǎn)登錄按鈕,通過頁面追蹤分析并模擬整個登錄過程,這個過程要尤其仔細(xì),因?yàn)楹芏郈AS在登錄頁面上埋了很多隱藏的標(biāo)記,一個地方模仿的不對可能就會登錄失敗然后又被重定向到開始的地方。


分析登錄過程

從分析可以看到,登錄按鈕提交的時候會用POST方式提交一個表格,而表格里面的除了賬號密碼等顯眼的字段以外還有一個lt,經(jīng)驗(yàn)告訴我們這個字段應(yīng)該隱藏在之前的登錄頁面上,用來校驗(yàn)登錄頁面的合法性,所以我們要從登錄頁面上找到并提取這個信息。同時還要注意http的消息頭,最好按照瀏覽器抓取的消息頭去構(gòu)造,因?yàn)榫W(wǎng)站同樣會校驗(yàn)這里面的信息。
下面是登錄的主要代碼,我們基于python3和requests包來處理https訪問請求,模擬瀏覽器的行為將認(rèn)證需要的信息構(gòu)造出來發(fā)給網(wǎng)站。

import requests
import urllib3
from lxml import etree

from ows_scrapy.ows_spider.write_csv import write_list_to_csv

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


s = requests.session()
s.trust_env = False     # faster
cookie = None

username = 'username'
password = 'pwd'


def login():
    header = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'keep-alive',
        'Cookie': 'JSESSIONID=73E10849812940333A4AD2A2ABAEFB7D8CFF3E76A45340FFB687FD587D2EB97A49FC5F156D09DB1E17F129465AB8D8EBACEC',
        'Host': '<your web url>',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
    }

    form_data = {
        'username': username,
        'password': password,
        '_eventId': 'submit',
        'pwdfirst':  password[0:2],
        'pwdsecond': password[2:5],
        'pwdthird': password[5:]
    }

    login_url = 'https://<your web url>.com/app/'
    print('login...')

    res = s.get(login_url, headers=header, verify=False)
    global cookie
    cookie = res.cookies    # 注意要保存cookie
    print("get response from ows {0}, http status {1}".format(login_url, res.status_code))

    login_url = res.url
    header['Referer'] = login_url
    header['Cookie'] = 'JSESSIONID=' + cookie['JSESSIONID']
    form_data['lt'] = str(etree.HTML(res.content).xpath('//input[@name="lt"]/@value')[0])   #用xpath從頁面上提取lt

    res = s.post(login_url, headers=header, params=form_data, cookies=cookie, allow_redirects=False, verify=False)
    cookie = res.cookies
    print("post login params to {0}, http status {1}, cookie : {2}".format(login_url, res.status_code, cookie))

    res = s.send(res.next, allow_redirects=False, verify=False)
    cookie = res.cookies
    print("redirect to {0}, http status {1}, cookie : {2}".format(login_url, res.status_code, cookie))

    if res.status_code == 200 or res.status_code == 302:
        if cookie is not None and cookie.get(name='JSESSIONID', path='/app') is not None :
            print('Successful login.')
        else:
            print('WRONG w3id/password!')
            sys.exit(0)

這里要特別注意一點(diǎn),因?yàn)閔ttp是無狀態(tài)的,web頁面要保存登錄狀態(tài)需要用到cookie,等成成功以后頁面的response里面會包含一個帶有有效標(biāo)記的cookie,登錄最終的目標(biāo)就是獲取并保存這個有效的cookie,這樣后續(xù)的訪問就不會被重定向到登錄頁。
在requests的方法里面只要向這樣吧cookie帶到請求里即可

res = s.post(login_url, headers=header, params=form_data, cookies=cookie, allow_redirects=False, verify=False)

分析動態(tài)內(nèi)容頁面

在動態(tài)頁面里,頁面上顯示出來的內(nèi)容往往都是js或者AJAX異步獲取到的,跟靜態(tài)html頁面的分析過程有明顯的不同。用Chrome的分析工具也可以很容易的獲取到該信息。


分析動態(tài)頁面

在動態(tài)頁面加載完成后,我們從所有的請求中過濾XHR類型,從中找到我們要的那一次請求,然后在該請求的Preview里面就可以看到完整的相應(yīng)信息,同時該請求的URL也可以從Headers選卡中得到。

接下來要做的事情跟上面類似,構(gòu)造報(bào)文模擬瀏覽器向該網(wǎng)站發(fā)送請求:

def get_content(order_id):
    form_data = {
        'roarand': 'BW09el5W3mW2sfbGbtWe7mWlwBsWqXg6znppnqkW3woJ5fcz5DnhfWXGonqkLsd0',
        'start': '0',
        'limit': '20',
        'orderid': order_id,
        'serviceId': 'test_gscsocsecurityincidentmanage_log_getList2'
    }

    header = {
        'Accept': 'text/plain, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'keep-alive',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        'Host': '<your web>.com',
        'Origin': 'https://<your web>.com',
        'Referer': 'https://<your web>.com/app/104h/spl/test/ID_480_1511441539904_workflowdetail.spl?orderid=SOC-20180220-00000003',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest'
    }
    print('Start to scan order id ' + order_id)

    url = 'https://<your web>.com/app/pageservices/service.do?forAccessLog={serviceName:test_gscsocsecurityincidentmanage_log_getList2,userId:571bdd42-10ca-4ce1-b41c-8a3f6632141f,tenantId:104h}&trackId=fec68f8e-f30a-4fa1-a8b1-41d3dd11fa4c'
    res = s.post(url, headers=header, params=form_data, cookies=cookie, allow_redirects=False, verify=False) #要加載上面登錄成功的cookie
    print(res.content)
    return res

要點(diǎn)其實(shí)就是從XHR里找到請求的URI,構(gòu)造請求報(bào)文頭和提交表格,最后務(wù)必要加上登錄成功的cookie,否則會被重定向到登錄頁面。

抓取動態(tài)頁面的方法還有很多,這種方法依賴的包相對較少,代碼比較靈活,在爬取復(fù)雜的登錄頁面的時候效果比較好,只是在分析頁面登錄機(jī)制的時候要尤其細(xì)心。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,697評論 19 139
  • HTTP cookie(也稱為web cookie,網(wǎng)絡(luò)cookie,瀏覽器cookie或者簡稱cookie)是網(wǎng)...
    留七七閱讀 18,390評論 2 71
  • 到目前為止,我們已經(jīng)會寫Angularjs的雙向數(shù)據(jù)綁定,那么今天也將一起來整理一下Vue.js的雙向數(shù)據(jù)綁定。簡...
    葉糖糖閱讀 412評論 0 1
  • 【三角梅】 今早上6:20起床推開窗,霜降后的三角梅依然熱鬧的開放著,讓人欣喜! 今年花開得好,從春天開到深秋,我...
    小梅弄堂閱讀 332評論 0 1

友情鏈接更多精彩內(nèi)容