Go 語(yǔ)言 爬蟲(chóng)實(shí)現(xiàn) v0.2

在之前上一版本中,我們通過(guò)最簡(jiǎn)單的 Get 請(qǐng)求獲取了網(wǎng)頁(yè)地址,并解析出圖片地址,然后再通過(guò) Get 請(qǐng)求獲取了圖片內(nèi)容。接下來(lái)的問(wèn)題是,對(duì)于有登陸限制的網(wǎng)頁(yè),登陸之前是看不到相關(guān)信息的,那么對(duì)于這一類(lèi)網(wǎng)頁(yè)該如何處理呢?


1. HTTP 請(qǐng)求與響應(yīng)的格式

參見(jiàn)這篇文章,我們知道,在瀏覽器發(fā)出 Get 或 Post 請(qǐng)求時(shí),請(qǐng)求的格式大致如下:

<request-line>
<headers>
<blank line>
[<request-body>]

瀏覽器在我們?cè)L問(wèn)網(wǎng)頁(yè)時(shí)會(huì)自動(dòng)構(gòu)造相關(guān)請(qǐng)求內(nèi)容,在 chrome 中 F12 過(guò)后看到的視圖下,選擇 Network 標(biāo)簽并選擇下方的 Headers 標(biāo)簽,然后刷新網(wǎng)頁(yè),隨意選擇 Headers 標(biāo)簽左邊 Name 欄下的任一元素(一般選第一個(gè))便可看到瀏覽器發(fā)送與接收消息時(shí),消息的 Header 中的內(nèi)容,如下圖:

微博截圖

我們需要用到的就是最下面紅色標(biāo)注的 Request Headers 部分的內(nèi)容 —— 即 cookie 字段


Request Headers

圖中的 cookie 即網(wǎng)站存儲(chǔ)在瀏覽器中的 cookie 值,我們將該 cookie 值復(fù)制出來(lái),粘貼在我們下一步將要在代碼中構(gòu)造的 Request Header 頭中,網(wǎng)站就會(huì)認(rèn)為我們已經(jīng)登錄過(guò)了。


2. Go net/http 包 client 介紹

為了能夠控制 HTTP 客戶端的頭結(jié)構(gòu),重定向規(guī)則以及其他一些設(shè)置, Go 在 net/http 中給了一個(gè) client 結(jié)構(gòu)體類(lèi)型,結(jié)構(gòu)詳情如下:

type Client struct {
    Transport RoundTripper 
    // CheckRedirect 明確了處理重定向的機(jī)制
    // 如果該字段不為 nil,則客戶端在重新請(qǐng)求重定向的鏈接之前,先執(zhí)行該函數(shù)
    CheckRedirect func(req *Request, via []*Request) error
    // CookieJar 是用來(lái)管理與使用眾多 HTTP 請(qǐng)求中的 cookies的
    Jar CookieJar
    Timeout time.Duration
}

在構(gòu)造 http 請(qǐng)求時(shí),我們先構(gòu)造一個(gè) client,用來(lái)模擬本地的客戶端的種種行為。 client 有這樣一些方法:

// Do 方法發(fā)送一個(gè) HTTP request 并獲得一個(gè) HTTP response
// 所以在調(diào)用之前需要先構(gòu)造一個(gè) request
func (c *Client) Do(req *Request) (*Response, error)
// Get 方法向給定的 URL 發(fā)送 Get 請(qǐng)求
func (c *Client) Get(url string) (resp *Response, err error)
// Head 方法向給定的 URL 發(fā)送一個(gè) Head
func (c *Client) Head(url string) (resp *Response, err error)
// Post 方法向給定的 URL 發(fā)送 Post 請(qǐng)求
func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error)
......

上一篇文章我們使用 http.Get() 方法發(fā)送了一個(gè) Get 請(qǐng)求,通過(guò)源碼我們看到, http.Get() 方法實(shí)際是構(gòu)造了一個(gè) DefaultClient = &Client{},再調(diào)用 Default.Get() 方法。而通過(guò)閱讀源碼發(fā)現(xiàn), func (c *Client) Get(url string) (resp *Response, err error) 方法的實(shí)現(xiàn)實(shí)際就是先構(gòu)造 Request 對(duì)象,再調(diào)用 Client.Do 方法,如下:

func (c *Client) Get(url string) (resp *Response, err error) {
    req, err := NewRequest("GET", url, nil)
    if err != nil {
        return nil, err
    }
    return c.Do(req)
}

總結(jié)來(lái)看,我們?cè)谑褂?Client 時(shí),先構(gòu)造一個(gè) Request 再調(diào)用 Client.Do() 方法。(關(guān)于 type Request struct詳見(jiàn)該鏈接下的相關(guān)內(nèi)容)

3. 代碼實(shí)現(xiàn)

該代碼沒(méi)有實(shí)現(xiàn)模擬登陸存取網(wǎng)站返回的cookie,只是簡(jiǎn)單驗(yàn)證了構(gòu)造 header 使用 http 包中 client 結(jié)構(gòu)體訪問(wèn)相關(guān)有驗(yàn)證網(wǎng)頁(yè)的可行性。代碼如下:

package main

import (
    "net/http"
    "fmt"
    "io/ioutil"
)

func check(err error){
    if err != nil {
        panic(err)
    }
}

func main(){
    url := "http://weibo.com/u/5765378903"
    client := &http.Client{}
    req, err := http.NewRequest("GET", url, nil)
    check(err)
    cookie_str := "your cookie"  //從瀏覽器復(fù)制的 cookie 字符串
    req.Header.Set("Cookie",cookie_str)
    resp, err := client.Do(req)
    check(err)
    resp_byte, err := ioutil.ReadAll(resp.Body)
    defer resp.Body.Close()
    fmt.Println(string(resp_byte))
}

最后結(jié)果表明該代碼能夠獲取所期望的網(wǎng)頁(yè)信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,886評(píng)論 18 139
  • scrapy學(xué)習(xí)筆記(有示例版) 我的博客 scrapy學(xué)習(xí)筆記1.使用scrapy1.1創(chuàng)建工程1.2創(chuàng)建爬蟲(chóng)模...
    陳思煜閱讀 12,769評(píng)論 4 46
  • Nginx API for Lua Introduction ngx.arg ngx.var.VARIABLE C...
    吃瓜的東閱讀 5,855評(píng)論 0 5
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒(méi)有聽(tīng)過(guò)Nginx?那么一定聽(tīng)過(guò)它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,781評(píng)論 24 1,002
  • 聽(tīng)不見(jiàn)的耳語(yǔ)最誠(chéng)懇,看不到的內(nèi)心最忠貞。 我們都想要牽了手就能結(jié)婚的愛(ài)情,卻活在一個(gè)上了床也沒(méi)有結(jié)果的年代。 對(duì)...
    趙小萌Q閱讀 549評(píng)論 0 1