golang 爬蟲簡單實戰

第一步先安裝 elasticsearch,因爲爬蟲數據量特別大,如果靠着我們手動刷新進入文件無疑非常耗費時間,所以數據用來存儲在 elasticsearch 上面,有這麼幾點好處

這裏我就用 docker 來進行安裝 elasticsearch 了

# 最好加上版本號 不然可能會報錯
docker run -d -p 9200:9200 elasticsearch:5.6.9
# 然後查看啓動狀態
docker ps

看到容器啓動成功後就可以通過 localhost:9200 訪問了~

對於爬蟲呢 ,其實沒那麼高大尚 ,我們在瀏覽器輸入一個 url,然後就進入我們想要的頁面,從 http 層面來看,我們發起一個 request 請求後,會有一個 response 響應,而我們需要的信息都在 response body 裏面,爬蟲就是把 response body 的數據經過正則的篩選然後拿到而已。

先看看一個入門的案例~

func zhai()  {
  resp, err := http.Get("https://www.zhenai.com/n/message?from=myzhenai")
  if err != nil {
    panic(err)
  }
  defer resp.Body.Close()
  //utf8Reader := transform.NewReader(resp.Body, simplifiedchinese.GBK.NewDecoder())
  if resp.StatusCode == http.StatusOK {
    all, err := ioutil.ReadAll(resp.Body)
    if err != nil {
      panic(err)
    }
    bytes := printWomen(all)
    for _, m := range bytes {
      for _, subMatch := range m {
        fmt.Printf("%s ", string(subMatch))
      }
      fmt.Println()
    }
    fmt.Println("找到 :", len(bytes))
  }
}
// 正則解析器
func printWomen(contents []byte) [][][]byte {
  re := regexp.MustCompile(`<a target="_blank" href="//(www.zhenai.com/zhenghun/[0-9a-zA-Z]+)".[^>]*>([^<]+)</a> `)
  matches := re.FindAllSubmatch(contents, -1)
  return matches
}
func main() {
  zhai()
}

這就是我們所爬取的信息~ 當然這是通過正則來達到的效果,正則表達式可以自己簡單瞭解下,很簡單的~

     網站一般都會有反爬機制,像上面這個網站沒有,但如果把網址換成豆瓣,大家就可以看到返回的狀態嗎是 418 了(俗稱茶壺狀態碼~),不過這種反爬只是通過 UA(User-Agent)來驗證是否是瀏覽器訪問還是代碼訪問而已,咱們弄個簡單的 UA 僞裝就行。

看上圖控制檯,那就是 UA 身份了,瀏覽器 f12 打開控制檯找到 Network 的 Request Headers 就可以看到我們自己的 UA 了,然後寫進代碼就行了

這兒就是設置了 UA 僞裝,這個時候就可以正常爬豆瓣了!

單機版爬蟲流程圖

下面上代碼

// 啓動函數 main方法
func main() {
  engine.Run(engine.Request{
    Url: "https://book.douban.com/",
    ParseFunc: parse.ParseContent,
  })
}
// engine包的type類
type Request struct {
  Url string
  ParseFunc func([]byte) ParseResult    //該函數用於參數解析 正則
}
type ParseResult struct {
  Requests []Request
  Items []interface{}
}
func NilParse([]byte) ParseResult {
  return ParseResult{}
}
// engine包的engine類
func Run(seeds ...Request)  {
  var requests []Request
  for _, e := range seeds {
    requests = append(requests, e)
  }
  for len(requests) > 0 {
    r := requests[0]
    requests = requests[1:]
    log.Printf("fetching url: %s", r.Url)
    body, err := fetcher.Fetch(r.Url)
    if err != nil {
      log.Printf("Fetch Error: %s", r.Url)
      continue
    }
    parseResult := r.ParseFunc(body)
    requests = append(requests, parseResult.Requests...)
    for _, item := range parseResult.Items {
      fmt.Printf("got item: %s\n", item)
    }
  }
}
// fetcher包的fetch類
func Fetch(url string) ([]byte, error) {
  client := &http.Client{}
  req, err := http.NewRequest("GET", url, nil)
  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36")
  resp, err := client.Do(req)
  if err != nil {
    panic(err)
  }
  defer resp.Body.Close()
  if resp.StatusCode != http.StatusOK {
    fmt.Printf("Error status code :%d", resp.StatusCode)
  }
  result, err := ioutil.ReadAll(resp.Body)
  return result, err
}
// 正則解析標籤 parse包下的parseTag類
const regexpStr = `<a href="([^"]+)">([^"]+)</a>`
func ParseContent(content []byte) engine.ParseResult{
  res := regexp.MustCompile(regexpStr)
  matches := res.FindAllSubmatch(content, -1)
  result := engine.ParseResult{}
  for _, m := range matches {
    result.Items = append(result.Items, m[2])
    result.Requests = append(result.Requests, engine.Request{
      Url: "https://book.douban.com/" + string(m[1]),
      ParseFunc: engine.NilParse,
    })
  }
  return result
}

這就是一個簡單的爬蟲了,幾乎可以訪問目前所有的網站了

類似淘寶這種大型網站其反爬機制肯定很難,但只要可以訪問,就一定可以爬,做好 UA 僞裝、cookie 認證、代理 ip、token 認證等一堆機制,也不是爬不了,當然爬到的內容都是咱們可以看到的,比如密碼這種東西,就不是爬蟲可以爬到的了,所以爬蟲也不是萬能的~

這是爬淘寶頁面的數據,並不是程序錯誤,只是每個人的 token 都不一樣,所以有些需要登陸才能訪問的頁面就會報錯 404,帶上自己的 token 就好了~

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/kU4gpf2AGQRcezy8s8T0nQ