Python에는 beautifulsoup 패키지가 존재해 Go에서도 없을까 찾아보던 도중 유사한 패키지를 찾았습니다. 해당 패키지를 사용하여 웹 크롤러를 만들거나 html에서 필요한 정보를 검색할 때, 편리하게 코딩할 수 있습니다.

설치

$ go get github.com/PuerkitoBio/goquery

사용법

아래는 현재 최신버전인 1.5 버전으로 설명합니다. 1.4이하 버전에서는 NewDocument()가 존재했지만 1.4버전에서 더이상 사용하지 않으므로 언급하지 않습니다.

package main

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

  "github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
  // Request the HTML page.
  res, err := http.Get("http://metalsucks.net")
  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(".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()
}


위는 타겟 사이트를 호출하여 원하는 데이터를 찾아가는 예시입니다. 아래에서는 test html을 생성 후 기능을 하나씩 설명한 예제입니다.

test html 생성 후 원하는 태그 찾기

검색은 html을 찾는 방식과 동일합니다.

태그 .클래스명 #아이디명

예시)

div 안에 있는 모든 p태그 찾기

  • div p

class=name 명 찾기

  • .name

id=err 명 찾기

  • #err

<div class=name> 찾기

  • div.name

<div class=name> <p>test</p> </div> 에서 p태그 내의 내용찾기

  • div.name p


아래는 a 태그를 찾는 예시입니다.

package main

import (
	"fmt"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
	// HTML 요청
	html := `
	<!DOCTYPE html>
<html>

<head>
   <title>Page title</title>
</head>

<body>
   <div>
      <p>a</p>
      <p>b</p>
      <p>c</p>
   </div>
   <div class="ex_class">
      <p>d</p>
      <p>e</p>
      <p>f</p>
   </div>
   <div id="ex_id">
      <p>g</p>
      <p>h</p>
      <p>i</p>
   </div>
   <h1>This is a heading</h1>
   <p>This is a paragraph.</p>
   <p>This is another paragraph.</p>
   <a href="http://brownbears.tistory.com" class="a"/>
</body>

</html>
	`
	rHtml := strings.NewReader(string(html))

	// HTML 문서 불러오기
	doc, err := goquery.NewDocumentFromReader(rHtml)
	if err != nil {
		panic(err)
	}

	// Find the review items
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		// 코드
		// fmt.Println(s.Text())
		
	})
}

func main() {
	ExampleScrape()
}

태그 사이에 있는 내용 출력

package main

import (
	"fmt"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
	// HTML 요청
	html := `
	<!DOCTYPE html>
<html>

<head>
   <title>Page title</title>
</head>

<body>
   <div>
      <p>a</p>
      <p>b</p>
      <p>c</p>
   </div>
   <div class="ex_class">
      <p>d</p>
      <p>e</p>
      <p>f</p>
   </div>
   <div id="ex_id">
      <p>g</p>
      <p>h</p>
      <p>i</p>
   </div>
   <h1>This is a heading</h1>
   <p>This is a paragraph.</p>
   <p>This is another paragraph.</p>
   <a href="http://brownbears.tistory.com" class="a"/>
</body>

</html>
	`
	rHtml := strings.NewReader(string(html))

	// HTML 문서 불러오기
	doc, err := goquery.NewDocumentFromReader(rHtml)
	if err != nil {
		panic(err)
	}

	// Find the review items
	doc.Find("h1").Each(func(i int, s *goquery.Selection) {
		fmt.Println(s.Text())

	})
}

func main() {
	ExampleScrape()
}

// This is a heading

태그 내의 속성값 출력

package main

import (
	"fmt"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
	// HTML 요청
	html := `
	<!DOCTYPE html>
<html>

<head>
   <title>Page title</title>
</head>

<body>
   <div>
      <p>a</p>
      <p>b</p>
      <p>c</p>
   </div>
   <div class="ex_class">
      <p>d</p>
      <p>e</p>
      <p>f</p>
   </div>
   <div id="ex_id">
      <p>g</p>
      <p>h</p>
      <p>i</p>
   </div>
   <h1>This is a heading</h1>
   <p>This is a paragraph.</p>
   <p>This is another paragraph.</p>
   <a href="http://brownbears.tistory.com" class="a"/>
</body>

</html>
	`
	rHtml := strings.NewReader(string(html))

	// HTML 문서 불러오기
	doc, err := goquery.NewDocumentFromReader(rHtml)
	if err != nil {
		panic(err)
	}

	// Find the review items
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		value, isExist := s.Attr("href")
		fmt.Println(value, isExist)

	})
}

func main() {
	ExampleScrape()
}


// http://brownbears.tistory.com true

복잡한 검색

아래는 ex_class라는 클래스명을 가진 div태그 내 p태그들의 내용을 찾는 쿼리입니다.

package main

import (
	"fmt"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
	// HTML 요청
	html := `
	<!DOCTYPE html>
<html>

<head>
   <title>Page title</title>
</head>

<body>
   <div>
      <p>a</p>
      <p>b</p>
      <p>c</p>
   </div>
   <div class="ex_class">
      <p>d</p>
      <p>e</p>
      <p>f</p>
   </div>
   <div id="ex_id">
      <p>g</p>
      <p>h</p>
      <p>i</p>
   </div>
   <h1>This is a heading</h1>
   <p>This is a paragraph.</p>
   <p>This is another paragraph.</p>
   <a href="http://brownbears.tistory.com" class="a"/>
</body>

</html>
	`
	rHtml := strings.NewReader(string(html))

	// HTML 문서 불러오기
	doc, err := goquery.NewDocumentFromReader(rHtml)
	if err != nil {
		panic(err)
	}

	// Find the review items
	doc.Find("div.ex_class p").Each(func(i int, s *goquery.Selection) {
		fmt.Println(s.Text())

	})
}

func main() {
	ExampleScrape()
}


만약 id명이 ex_id를 가진 div태그 내의 모든 p태그들에 대한 내용을 가지고 오고 싶을 경우, div.ex_class p 가 아닌 div#ex_id p 로 검색하면 됩니다.


더 많은 정보는 https://github.com/PuerkitoBio/goquery 에서 확인할 수 있습니다.

+ Random Posts