1. 檢查請求
首先來到Github的登錄頁面,如下所示。

然后打開開發(fā)者模式,切換到Netword選項(xiàng)卡下,然后在瀏覽器輸入用戶名和密碼,不要著急點(diǎn)擊登錄,先清除Network下的所有請求。
然后點(diǎn)擊登錄,會(huì)看到有很多的請求被發(fā)送出去。
接著找到第一個(gè)session請求,查看該post請求的form data,如下圖所示。

其中的login 和 password就是我們所輸入的賬號名與密碼。那么,接下來的模擬過程就是我們只需要構(gòu)造這個(gè)form data然后往該請求的request URL發(fā)送數(shù)據(jù)就可以完成模擬登錄。
經(jīng)過分析可以發(fā)現(xiàn),我們需要構(gòu)造的參數(shù)有authenticity_token,ga_id , timestamp,timestamp_secret這四個(gè)參數(shù),其他的例如commit ,utf8,webauth-invpaa-support 等可以直接復(fù)制。
2.構(gòu)造請求參數(shù)
那么,我們要怎樣構(gòu)造所需要的四個(gè)參數(shù)呢?
2.1 authenticity_token
我們還是在登錄頁面打開開發(fā)者模式,不用輸入賬戶密碼進(jìn)行登錄,然后切換到Element選項(xiàng)下,在該頁面下搜索token,發(fā)現(xiàn)只有一個(gè)搜索結(jié)果。

這個(gè)input元素里的value值就是authenticity_token的值,我們只需通過xpath選擇器選擇該節(jié)點(diǎn),然后取其value屬性即可。該xpath表達(dá)式為://input[@name="authenticity_token"]/@value
。
2.2 timestamp與timestamp_secret
同樣,我們搜索timestamp可以同時(shí)發(fā)現(xiàn)timestamp與tiemstamp_secret兩個(gè)參數(shù)。

其value值也就是我們需要的參數(shù)值。
然后通過xpath選出該值。
timestamp://input[@name="timestamp"]/@value
timestamp_secret://input[@name="timestamp_secret"]/@value
2.3 ga_id
跟上面的思路一樣,我們可以通過同樣的方式找出ga_id,一共有兩個(gè)搜索結(jié)果,一個(gè)是head 里的meta信息,還有一個(gè)是登錄表單里的信息。


這兩個(gè)元素里都有我們需要的值,meta里的content內(nèi)容和inp里的value值就是ga_id 的值,而且這兩個(gè)值是一樣的。照理,我們也可以用xpath提取到ga_id的值。但是在程序完成之后,我們發(fā)現(xiàn)其他的值都可以提取出來,而ga_id提取的出來的值卻為空,其原因是該元素是通過js動(dòng)態(tài)加載的,在程序里是提取不到這個(gè)值的。所以,在這個(gè)地方我們有兩種解決辦法,一個(gè)是閱讀js的代碼,找到ga_id的生成方法后自己生成一個(gè)ga_id,還有一種是通過Selenium加載頁面,然后按照xpath提取值。在這里我們選用第二種方法,因?yàn)檫@種方法快速簡潔而方便。
def ga_id(self):
broser = webdriver.Chrome()
broser.get(self.login_url)
time.sleep(5)
html = broser.page_source
html = etree.HTML(html)
ga_id = html.xpath('//div//input[@name="ga_id"]/@value')[0]
return ga_id
這里要用Chrome驅(qū)動(dòng),用Phantomjs驅(qū)動(dòng)依然提取不到值。
這樣,我們需要的請求參數(shù)都構(gòu)造完成了,接下來發(fā)送請求就可以了。
3.發(fā)送請求
def login(self):
formdata = {
'commit':'Sign in',
'utf8':'√',
'authenticity_token':self.token(),
'ga_id':self.ga_id(),
'login':賬號名,
'password':密碼,
'webauthn-support':'',
'webauthn-iuvpaa-support':'',
'timestamp':self.timestamp(),
'timestamp_secret':self.timestamp_secret()
}
response = self.session.post(self.post_url,data=formdata,headers=self.headers)
# 測試登錄后的頁面
zhuye = self.session.get('https://github.com/settings/keys',headers =self.headers)
print(zhuye.text)
運(yùn)行代碼可以發(fā)現(xiàn)其輸出了登錄后才能顯示的頁面,也就模擬登錄成功了。
完整代碼如下:
# coding-utf-8
import time
import requests
from lxml import etree
from selenium import webdriver
class Login(object):
def __init__(self):
self.headers = {
"Origin":"https://github.com",
"Host":"github.com",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0"
}
self.login_url = "https://github.com/login"
self.post_url = "https://github.com/session"
self.session = requests.Session()
self.lresponse = self.session.get(self.login_url, headers=self.headers)
self.html = etree.HTML(self.lresponse.text)
def token(self):
token = self.html.xpath('//input[@name="authenticity_token"]/@value')[0]
return token
def ga_id(self):
broser = webdriver.Chrome()
broser.get(self.login_url)
time.sleep(5)
html = broser.page_source
html = etree.HTML(html)
ga_id = html.xpath('//div//input[@name="ga_id"]/@value')[0]
return ga_id
def timestamp(self):
tiemstamp = self.html.xpath('//input[@name="timestamp"]/@value')[0]
return tiemstamp
def timestamp_secret(self):
tiemstamp_secret = self.html.xpath('//input[@name="timestamp_secret"]/@value')[0]
return tiemstamp_secret
def login(self):
formdata = {
'commit':'Sign in',
'utf8':'√',
'authenticity_token':self.token(),
'ga_id':self.ga_id(),
'login':賬號,
'password':密碼,
'webauthn-support':'',
'webauthn-iuvpaa-support':'',
'timestamp':self.timestamp(),
'timestamp_secret':self.timestamp_secret()
}
response = self.session.post(self.post_url,data=formdata,headers=self.headers)
# 測試登錄后的頁面
zhuye = self.session.get('https://github.com/settings/keys',headers =self.headers)
print(zhuye.text)
if __name__ =="__main__":
github = Login()
github.login()