Job 스크랩 (2)

박도준·2021년 3월 6일
0

Golang

목록 보기
2/3

+ indeed 페이지 수 받아오기

  • 각 페이지 URL 생성
  • 페이지로부터 일자리 추출
  • 추출한 job들의 정보를 엑셀에 담기


⭐ 각 페이지 URL 생성

이제 baseURL과 받아온 페이지 수를 통해 각 페이지의 URL을 만든다.
실제 페이지 URL을 보면 페이지가 넘어갈때마다 &start= 값이 바뀌는 것을 볼 수 있다.

이를 이용해 아래와 같이 페이지를 생성한다.

func main() {
	totalPages := getPages()
	for i := 0; i < totalPages; i++ {
		getPage(i)
	}
}

func getPage(page int) {
	pageURL := baseURL + "&start=" + strconv.Itoa(page*10)
}


⭐ 페이지로부터 일자리 추출

각 페이지에는 일자리의 카드가 존재한다.
jobsearch-SerpJobCard 클래스를 Find하여 각 일자리들의 카드를 가져와 일자리의 정보를 추출한다.

각각의 일자리에 대한 정보를 구조체를 만들어 관리한다.

type extractedJob struct {
	id       string
	title    string
	location string
	salary   string
	summary  string
}

이때 바로 값을 받아오면 문자 뒤로 공백(space)가 많기 때문에 이를 제거해주는 작업이 필요하다.

3가지 메서드를 사용하는데 우선 TrimSpace() 메서드를 통해 선행과 후행의 공백을 없앤다.

그리고 Fields()메서드로 문자를 분리하여 배열을 만든다. 지금까지의 과정을 수행하면 공백이 없는 문자들이 배열에 들어 있게 된다.

배열에 있는 문자들을 separator 포함한 하나의 문자열로 만들길 위해 Join() 메서드를 사용한다.

func getPage(page int) {
	defer res.Body.Close()

	doc, err := goquery.NewDocumentFromReader(res.Body)
	checkErr(err)

	searchCards := doc.Find(".jobsearch-SerpJobCard")
	searchCards.Each(func(i int, card *goquery.Selection) {
		job := extractJob(card)
	})
}

func extractJob(card *goquery.Selection) extractedJob {
	id, _ := card.Attr("data-jk")
	title := cleanString(card.Find(".title>a").Text())
	location := cleanString(card.Find(".sjcl").Text())
	salary := cleanString(card.Find(".salaryText").Text())
	summary := cleanString(card.Find(".summary").Text())
	return extractJob{
		id:       id,
		title:    title,
		location: location,
		salary:   salary,
		summary:  summary}
}

func cleanString(str string) string {
	return strings.Join(strings.Fields(strings.TrimSpace(str)), " ")
}

지금까지의 전체 코드

package main

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

	"github.com/PuerkitoBio/goquery"
)

var baseURL string = "https://kr.indeed.com/jobs?q=golang"

type extractedJob struct {
	id       string
	title    string
	location string
	salary   string
	summary  string
}

func main() {
	var jobs []extractedJob
	totalPages := getPages()
	for i := 0; i < totalPages; i++ {
		extractedJobs := getPage(i)
		jobs = append(jobs, extractedJobs...) //extractedJobs를 각각의 배열로 저장하는 것이 아닌
		// 하나의 배열로 만들기 위해 contents를 가져온다. 이때 ... 이용
	}
	fmt.Println(jobs)
}

func getPage(page int) []extractedJob { //하나의 페이지에 있는 일자리 추출
	var jobs []extractedJob

	pageURL := baseURL + "&start=" + strconv.Itoa(page*10)
	fmt.Println("Requesting", pageURL)
	res, err := http.Get(pageURL)
	checkErr(err)
	checkCode(res)

	defer res.Body.Close()

	doc, err := goquery.NewDocumentFromReader(res.Body)
	checkErr(err)

	searchCards := doc.Find(".jobsearch-SerpJobCard")
	searchCards.Each(func(i int, card *goquery.Selection) {
		job := extractJob(card)
		jobs = append(jobs, job)
	})

	return jobs
}

func extractJob(card *goquery.Selection) extractedJob { //카드에서 일자리 정보 추출
	id, _ := card.Attr("data-jk")
	title := cleanString(card.Find(".title>a").Text())
	location := cleanString(card.Find(".sjcl").Text())
	salary := cleanString(card.Find(".salaryText").Text())
	summary := cleanString(card.Find(".summary").Text())
	return extractedJob{
		id:       id,
		title:    title,
		location: location,
		salary:   salary,
		summary:  summary}
}

func cleanString(str string) string {
	return strings.Join(strings.Fields(strings.TrimSpace(str)), " ")
}

func getPages() int { /
	pages := 0
	res, err := http.Get(baseURL)
	checkErr(err)
	checkCode(res)


	defer res.Body.Close()


	doc, err := goquery.NewDocumentFromReader(res.Body) //res.Body는 기본적으로 byte
	checkErr(err)

	doc.Find(".pagination").Each(func(i int, s *goquery.Selection) {
		pages = s.Find("a").Length() //pagination 클래스 내에 링크 갯수
	})

	return pages

}

// 에러를 계속 체크해줘야 하기 때문에 따로 함수를 만들어서 처리

func checkErr(err error) {
	if err != nil { //에러가 있다면
		log.Fatalln(err) //프로그램 끝내기
	}
}

func checkCode(res *http.Response) { //http.Get()에서 http.Response의 포인터이기 때문에 앞에 * 를 붙여준다.
	if res.StatusCode != 200 {
		log.Fatalln("Request failed with Status: ", res.StatusCode)
	}
}


👉 Job 스크랩 (3)

profile
Better late than never

0개의 댓글