補充說明:按照本文方式,之所以能成功獲取登錄后的網頁,實際上是由於在代碼中使用了瀏覽器成功登錄后的cookie,此時服務器上SessionID有效。而一旦從瀏覽器中注銷登錄,本代碼也就無法訪問登錄后的網頁。
因此,正確方式請參考下一篇文章:https://www.cnblogs.com/pu369/p/12307162.html
前幾篇文章摸索了如何用golang模擬登錄;對簡單的情況,甚至可以用GET方式代替POST方式登錄。
但現在想抓取公司OA系統的網頁,就遇到一些困難。
難點:
1、登錄頁POST提交后,會有http 302跳轉。后來發現似乎不是問題,因為用http.Client.Do會自動處理跳轉。
2、網站使用了FrameSet,還有大量jquery動態生成加載內容,這個處理起來比較困難,鏈接也是JS生成,只能針對具體問題具體分析。
3、用chrome控制台抓到的header提交不成功,於是想到fiddler抓包,正好電腦上曾經下載過一個漢化版。
過程(主要是解決了POST登錄問題):
1、參考https://blog.csdn.net/qq_24373725/article/details/80584810 用fiddler抓包(我下載的漢化版本一啟動就自動抓所有包,感覺很方便,就是不知道有無后門),在過濾器中設置服務器網址:192.168.132.80;在 規則-自動斷點處-勾選 在請求之前。
2、在IE中從登錄頁輸入用戶名、密碼后提交登錄。就會在fiddler中抓到表單對應的提交網址:/login/VerifyLogin.jsp,接着在斷點處中斷了。點擊相應的: 運行到結束,或:中斷響應(對於rameset中的一些頁面可以中斷響應,框架網頁的一部分會顯示空白),經過幾次鼠標點擊操作,一串頁面先后執行完畢。
3、最重要的還是form表單對應的/login/VerifyLogin.jsp頁(其他網頁其實沒什么用),查看抓包到的原始數據為(我將用戶名和密碼改了:-)
POST http://192.168.132.80/login/VerifyLogin.jsp HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Referer: http://192.168.132.80/wui/theme/ecology7/page/login.jsp?templateId=6&logintype=1&gopage=&languageid=7&message=16 Accept-Language: zh-CN User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: 192.168.132.80 Content-Length: 284 Connection: Keep-Alive Pragma: no-cache Cookie: logincookiecheck=1581132245967+C1D3FCB434C8223BE9C4CE5AD9497183; JSESSIONID=abc67CXfxpBtu9aM2VR-w; testBanCookie=test; loginfileweaver=%2Fwui%2Ftheme%2Fecology7%2Fpage%2Flogin.jsp%3FtemplateId%3D6%26logintype%3D1%26gopage%3D; loginidweaver=114; languageidweaver=7 loginfile=%2Fwui%2Ftheme%2Fecology7%2Fpage%2Flogin.jsp%3FtemplateId%3D6%26logintype%3D1%26gopage%3D&logintype=1&fontName=%CE%A2%EF%BF%BD%EF%BF%BD%EF%BF%BD%C5%BA%EF%BF%BD&message=16&gopage=&formmethod=post&rnd=&serial=&username=&isie=true&loginid=admin&userpassword=1234&submit=
4、試着將上述數據寫入go代碼中,直接上代碼:
//參考:https://blog.csdn.net/kenkao/article/details/88844212 //http.Get http.Post http.PostForm http.Client.Do四種請求方式 //https://blog.csdn.net/qq_24373725/article/details/80584810 package main import ( "fmt" "io/ioutil" "net/http" "net/http/cookiejar" // "net/url" "strings" "time" "golang.org/x/text/encoding/simplifiedchinese" ) type MySpider struct { indexUrl string cleint *http.Client } //登錄,用POST請求 func (this MySpider) login() (string, error) { //訪問首頁 resp, err := this.cleint.Get(this.indexUrl) defer resp.Body.Close() time.Sleep(time.Duration(300) * time.Microsecond) //POST提交 //post_arg := url.Values{"loginid": {"admin"}, "userpassword": {"1234"}} post_arg := "loginfile=%2Fwui%2Ftheme%2Fecology7%2Fpage%2Flogin.jsp%3FtemplateId%3D6%26logintype%3D1%26gopage%3D&logintype=1&fontName=%CE%A2%EF%BF%BD%EF%BF%BD%EF%BF%BD%C5%BA%EF%BF%BD&message=16&gopage=&formmethod=post&rnd=&serial=&username=&isie=true&loginid=admin&userpassword=1234&submit=" //fmt.Println(post_arg.Encode()) //req, err := http.NewRequest("POST", "http://192.168.132.80/login/VerifyLogin.jsp", strings.NewReader(post_arg.Encode())) req, err := http.NewRequest("POST", "http://192.168.132.80/login/VerifyLogin.jsp", strings.NewReader(post_arg)) if err != nil { // handle error } req.Header.Set("Accept", "text/html, application/xhtml+xml, */*") req.Header.Set("Referer", "http://192.168.132.80/wui/theme/ecology7/page/login.jsp?templateId=6&logintype=1&gopage=&languageid=7&message=16") req.Header.Set("Accept-Language", "zh-CN") req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept-Encoding", "gzip, deflate") req.Header.Set("Host", "192.168.132.80") req.Header.Set("Content-Length", "284") req.Header.Set("Connection", "keep-alive") req.Header.Set("Pragma", "no-cache") req.Header.Set("Cookie", "logincookiecheck=1581132245967+C1D3FCB434C8223BE9C4CE5AD9497183; JSESSIONID=abc67CXfxpBtu9aM2VR-w; testBanCookie=test; loginfileweaver=%2Fwui%2Ftheme%2Fecology7%2Fpage%2Flogin.jsp%3FtemplateId%3D6%26logintype%3D1%26gopage%3D; loginidweaver=114; languageidweaver=7") //req.Header.Set("Cache-Control", "no-cache") //req.Header.Set("Origin", "http://192.168.132.80") //req.Header.Set("Upgrade-Insecure-Requests:", "1") a := req.Header.Get("Referer") fmt.Println(string(a)) //b, err := ioutil.ReadAll(req.Body) //fmt.Println(string(b)) resp, err = this.cleint.Do(req) defer resp.Body.Close() reader := simplifiedchinese.GB18030.NewDecoder().Reader(resp.Body) body, err := ioutil.ReadAll(reader) if err != nil { // handle error } fmt.Println(string(body)) //訪問登錄后才能訪問的頁面 resp, err = this.cleint.Get("http://192.168.132.80/CRM/data/CustomerBrowser.jsp?splitflag=") defer resp.Body.Close() //time.Sleep(time.Duration(1000) * time.Microsecond) reader = simplifiedchinese.GB18030.NewDecoder().Reader(resp.Body) body, err = ioutil.ReadAll(reader) fmt.Println(string(body)) return "", err } //運行 func (this MySpider) run() string { //生成可復用的client var client http.Client jar, err := cookiejar.New(nil) if err != nil { panic(err) } client.Jar = jar this.cleint = &client //登錄,用GET代替POST請求 this.login() return "" } func main() { //爬蟲實例 ms := new(MySpider) //入口地址http://192.168.133.16:8080 ms.indexUrl = "http://192.168.132.80/wui/theme/ecology7/page/login.jsp" ms.run() }
讓人感到高興的是,代碼中:
1.http.NewRequest 所需參數,也就是表單數據,應該叫body部分吧(與http頭 有一個空行間隔開),可以直接從抓包到的 原始 數據 中一次復制出來。見代碼中的post_arg變量值。
2.http header(請求頭部分)也可直觀在從抓包到的 原始 數據 中看到。即代碼中req.Header.Set設置的那些http頭內容。
當然,遺留的問題還較難解決,如:獲取jquery異步加載,打開javascript鏈接對應的網址、找frameset中的元素。解決辦法應該還是要用headless無頭瀏覽器處理。
也可用chrome控制台獲取http頭和formdata,還可以方便查看XHR異步加載請求。參考:https://www.cnblogs.com/LXP-Never/p/11374795.html(這位園主關於爬蟲的幾篇文章不錯)
但有的請求chrome console截獲不到,還得用fiddler.