登錄網站爬蟲(保持Cookie不變)


平時經常需要到學校的信息門戶去查看課表及其他信息,於是想做一個爬蟲 ,可以自動替我登錄並且得到這些信息,於是今天動手寫了一個爬蟲:

首先登錄學校的信息門戶:http://cas.whu.edu.cn/authserver/login?service=http://my.whu.edu.cn

然后這里我隨便輸入賬號名和密碼,來看看登錄時瀏覽器都做了些什么。這里我使用的是FireFix瀏覽器以及HttpFox插件,如果用Chrome的話,谷歌下也有很棒的插件,IE的話推薦HTTPWatch。

從HttpFox中我們可以分析得出大概流程,首先就是瀏覽器根據Name獲取到html中表單中的input內容,然后通過post提交到一個服務器地址,然后服務器判斷用戶名密碼是否正確,進而做出相應的響應。接下來我們就需要知道瀏覽器是把什么數據提交到了哪里,我們點擊httpfox中的第一個步驟:

可以看到瀏覽器把數據還是提交到了當前頁面,並且攜帶有Cookie,我們再看看postdata里都有什么

 

可以看到postdata中不僅有用戶名密碼,還有一些其他數據,到這里我們可以用Python寫一個爬蟲,只提交用戶名密碼,然后你會發現服務器還是給你返回一個登錄頁面,這時候我們就需要考慮lt dllt這些postdata了,可是這些是什么呢?我查閱了一些資料,lt可以理解成每個需要登錄的用戶都有一個流水號。只有有了webflow發放的有效的流水號,用戶才可以說明是已經進入了webflow流程。否則,沒有流水號的情況下,webflow會認為用戶還沒有進入webflow流程,從而會重新進入一次webflow流程,從而會重新出現登錄界面。

那么如何獲得這個lt數據呢。我們回到http://cas.whu.edu.cn/authserver/login?service=http://my.whu.edu.cn,按F12,

 

我們很容易能找到用戶名和密碼的兩個input,我們在查找input標簽:

發現在form最下面有這幾個隱藏域,現在我們已經拿到了流水號,可是還有一個問題:就是我首先發送一個get,然后我拿到這個隱藏域所有value,然后我需要在發送一次post方式,這時候,我們先前獲得的lt值已經不再是現在的lt值了,所以這個時候我們就要用requests的session方法來保持cookie不變了,session方法可以讓同一個實例發出的所有請求保持相同的cookie。

接下來任務就好做了:

#encode=utf8
'''
Created on 2016年10月15日

@author: WangHui
@note: View things from WuHanUniversity
'''
import requests
from http.cookiejar import CookieJar
from bs4 import BeautifulSoup

class WHUHelper(object):
    __loginuri='http://cas.whu.edu.cn/authserver/login?service=http://my.whu.edu.cn'
    __logindo='http://yjs.whu.edu.cn'
    #初始化構造函數,賬戶和密碼
    def __init__(self,name='',password=''):
        #賬戶名
        if not isinstance(name,str):
            raise TypeError('請輸入字符串')
        else:
            self.name=name
        if isinstance(password,int):
            self.password=str(password)
        elif isinstance(password, str):
            self.password=password
        else:
            raise TypeError('請輸入字符串')
    #返回一個登陸成功后的Response
    def __getResponseAfterLogin(self):
        #模擬一個瀏覽器頭
        header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0'}
        #保持Cookie不變,然后再次訪問這個頁面
        s=requests.Session()
        #CookieJar可以幫我們自動處理Cookie
        s.cookies=CookieJar()
        #得到一個Response對象,但是此時還沒有登錄
        r=s.get(self.__loginuri,headers=header)
        #得到postdata應該有的lt
        #這里使用BeautifulSoup對象來解析XML
        dic={}
        lt=BeautifulSoup(r.text,'html.parser')
        for line in lt.form.findAll('input'):
            if(line.attrs['name']!=None):
                dic[line.attrs['name']]=line.attrs['value']
        params={
            'username':self.name,
            'password':self.password,
            'dllt':'userNamePasswordLogin',
            'lt':dic['lt'],
            'execution':dic['execution'],
            '_eventId':dic['_eventId'],
            'rmShown':dic['rmShown']}
        #使用構建好的PostData重新登錄,以更新Cookie
        r=s.post(self.__loginuri, data=params,headers=header)
        #返回登錄后的response
        return s
    #得到研究生信息門戶指定分類下的HTML
    def __getHtmlOfPerson(self):
        s=self.__getResponseAfterLogin()
        personUri='http://yjs.whu.edu.cn/ssfw/index.do#'
        r=s.get(personUri)
        return r.text
    #得到研究生個人信息
    def getPersonInfor(self):
        s=self.__getResponseAfterLogin()
        bs=BeautifulSoup(self.__getHtmlOfPerson(),'html.parser')
        dic={}
        #得到基本信息get方式的訪問URL網站
        jbxxUri=self.__logindo+bs.find('a',{'text':'基本信息'}).attrs['url']
        r=s.get(jbxxUri)
        bs=BeautifulSoup(r.text,'html.parser')
        dic['學號']=bs.find('input',{'name':'jbxx.xh'}).attrs['value']
        dic['姓名']=bs.find('input',{'name':'jbxx.xm'}).attrs['value']
        return dic
    #得到個人課表
    def getClassInfo(self):
        #初始化課表
        classInfo=[]
        classTitle=['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
        for i in range(13):
            singleclass=[]
            for j in range(7):
                singleclass.append('')
            classInfo.append(singleclass)
        #首先得到登陸后的request
        s=self.__getResponseAfterLogin()
        bs=BeautifulSoup(self.__getHtmlOfPerson(),'html.parser')
        jbxxkb=self.__logindo+bs.find('a',{'text':'我的課表'}).attrs['url']
        r=s.get(jbxxkb)
        bs=BeautifulSoup(r.text,'html.parser')
        #得到每天十三節課
        trs=bs.find('table',{'class':'table_con'}).findAll('tr',{'class':'t_con'})
        for i in range(len(trs)):
            tds=trs[i].findAll('td')
            #表示星期幾
            j=0
            for td in tds: 
                #首先去掉table的行標題和列標題
                #根據規律可知,凡是帶有標題的都含有b標簽
                if td.find('b')!=None:
                    continue
                #beautifulsoup會把 解析為\a0,所以這里需要先轉碼,然后在編碼
                classInfo[i][j]=str(td.get_text()).encode('gbk','ignore').decode('gbk')
                j=j+1
        classInfo.insert(0, classTitle)        
        return classInfo

當然這個類並不完善,我只是想要看到我的課表,如果需要查看其他信息,可以使那個requests再次發送請求,然后用BeautifulSoup4解析即可。

這里我們可以測試一下:

 

參考文章:

https://my.oschina.net/u/1177799/blog/491645

http://beautifulsoup.readthedocs.io/zh_CN/latest/

http://m.blog.csdn.net/article/details?id=51628649

http://docs.python-requests.org/en/latest/user/advanced/#session-objects


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM