-
[Golang] BeautifulSoup 사용하기 (goquery 사용하기)언어/Golang 2019. 1. 19. 16:24
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 에서 확인할 수 있습니다.