golang爬虫

网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。

其实通俗的讲就是通过程序去获取web页面上自己想要的数据,也就是自动抓取数据

爬虫的基本流程

发起请求
通过HTTP库向目标站点发起请求,也就是发送一个Request,请求可以包含额外的header等信息,等待服务器响应

获取响应内容
如果服务器能正常响应,会得到一个Response,Response的内容便是所要获取的页面内容,类型可能是HTML,Json字符串,二进制数据(图片或者视频)等类型

解析内容
得到的内容可能是HTML,可以用正则表达式,页面解析库进行解析,可能是Json,可以直接转换为Json对象解析,可能是二进制数据,可以做保存或者进一步的处理

保存数据
保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件

示例

简单爬取博文

package main

import (
    "bufio"
    "errors"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "path"
    "strconv"
    "strings"
    "time"

    "github.com/PuerkitoBio/goquery"
)

func ExampleScrape(url, name string) error {
    // Request the HTML page.
    log.Println(url)
    res, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    if res.StatusCode != 200 {
        log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
    }

    // Load the HTML document
    doc, err := goquery.NewDocumentFromReader(res.Body)
    if err != nil {
        log.Fatal(err)
    }

    // Find the review items
    doc.Find("#mainContent .postTitle a").Each(func(i int, s *goquery.Selection) {
        var fileName string
        // For each item found, get the band and title
        title := s.Text()
        urlp, ok := s.Attr("href")
        if ok {
            _, fileName = path.Split(urlp)

            fmt.Printf("Review %d: %s - %s - %s\n", i, title, urlp, fileName)
            storeData(urlp, fileName)

            s.SetAttr("href", fileName)
        }
    })

    doc.Find("#homepage_bottom_pager .pager a").Each(func(i int, s *goquery.Selection) {
        strHref, ok := s.Attr("href")
        if ok {
            sliceHref := strings.Split(strHref, "=")
            if len(sliceHref) == 2 {
                s.SetAttr("href", "index"+sliceHref[1]+".html")
            }
        }
    })

    docStr, err := goquery.OuterHtml(doc.Selection)
    if err != nil {
        log.Fatal(err)
    }
    writeFileString(name, docStr)
    return nil
}

func writeFileString(fileName, info string) error {
    file, err := os.Create(fileName)
    if err != nil {
        return err
    }
    defer file.Close()

    file.WriteString(info)
    file.Sync()
    return nil
}

func writeFile(fileName string, info io.Reader) error {
    file, err := os.Create(fileName)
    if err != nil {
        return err
    }
    defer file.Close()

    wfile := bufio.NewWriter(file)
    defer wfile.Flush()

    _, err = wfile.ReadFrom(info)
    if err != nil {
        return err
    }
    return nil
}

func storeData(url, fileName string) error {
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    if resp.StatusCode != 200 {
        return errors.New(fmt.Sprintf("Get %s error and error code is %d\n", url, resp.StatusCode))
    }
    return writeFile(fileName, resp.Body)
}

func main() {
    var i int
    for i = 1; i < 80; i++ {
        url := "https://www.cnblogs.com/embedded-linux/default.html?page=" + strconv.Itoa(i)
        indexUrl := "index" + strconv.Itoa(i) + ".html"
        err := ExampleScrape(url, indexUrl)
        if err != nil {
            break
        }
        time.Sleep(1 * time.Second)
    }
}

 

反爬虫

有爬取网页的方法,自然有反爬虫,阻止爬取网页。

1. HTTP返回418,如 爬取豆瓣电影Top250

触发了反爬,返回一个彩蛋,因为你和 618 只差一个 HTTP 200 ……

参考:打开网站URL遇到“HTTP Error 418:”问题

在使用浏览器访问网站时,访问请求中包含请求头。检测请求头是常见的反爬虫策略。

服务器通过检测请求头判断这次请求是不是人为的。

在程序上加入请求头,这样服务器就会认为这是一个从浏览器发出的人为请求:

  req.Header.Add("User-Agent", `Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML,like GeCKO) Chrome/45.0.2454.85 Safari/537.36 115Broswer/6.0.3`)
package main

import (
  "fmt"
  "log"
  "net/http"

  "github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
  // Request the HTML page.
  client := &http.Client{}
  req, err := http.NewRequest("GET", "http://movie.douban.com/top250", nil)
  if err != nil {
    log.Fatal(err)
  }
  req.Header.Add("User-Agent", `Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML,like GeCKO) Chrome/45.0.2454.85 Safari/537.36 115Broswer/6.0.3`)
  req.Header.Add("Referer", "https://movie.douban.com/top250")
  req.Header.Add("connection", "keep-alive")
  res, err := client.Do(req) 
  if err != nil {
    log.Fatal(err)
  }
  defer res.Body.Close()
  log.Println(res)
  if res.StatusCode != 200 {
    log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
  }

  // Load the HTML document
  doc, err := goquery.NewDocumentFromReader(res.Body)
  if err != nil {
    log.Fatal(err)
  }

  // Find the review items
  doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
    // For each item found, get the band and title
    band := s.Find("a").Text()
    title := s.Find("i").Text()
    fmt.Printf("Review %d: %s - %s\n", i, band, title)
  })
}

func main() {
  ExampleScrape()
}
http://movie.douban.com/top250

 

参考:

1. 用Golang写爬虫(一)

2. python爬虫

3. 深入浅出爬虫之道: Python、Golang与GraphQuery的对比

4. 数据分析 爬虫了解一下Golang的市场行情  爬取汽车之家 二手车产品库 爬取豆瓣电影Top250

5. Golang爬虫全攻略 

posted @ 2020-03-22 22:48  yuxi_o  阅读(959)  评论(0编辑  收藏  举报