고랭지농업

크롤러 만들기[3] - 웹 페이지 구현 및 수집 테스트

했던 거 이어서 쓰겠습니다.

코드를 직접 치는거라 오타가 있을 수도 있습니다.

궁금한 점이나 문의..?? 등 댓글로 남겨주시면 제가 아는 선에서 설명드리겠습니다.

 

 

/public/crawl.html

- 목록 페이지 URL, 목록 정규표현식, 게시물 제목 정규표현식, 게시물 본문 정규표현식을 입력받습니다.

[code]

<!DOCTYPE HTML>

<html>

    <head>

        <title>크롤러</title>

    </head>

    <body>

        <form name="crawl" action="/crawl" method="post">

            <p>

                <input id="url" name="url" type="text">

                <label for="url">목록 페이지 URL</label>

           </p>

           <p>

               <input id="regex_url" name="regex_url" type="text">

               <label for="regex_url">목록 페이지 정규표현식</label>

           </p>

           <p>

               <input id="regex_subject" name="regex_subject" type="text">

               <label for="regex_subject">게시물 제목 정규표현식</label>

           </p>

           <p>

               <input id="regex_content" name="regex_content" type="text">

               <label for="regex_content">게시물 본문 정규표현식</label>

           </p>

           <button type="submit">

                실행

            </button>

        </form>

    </body>

</html>

[/code]

 

이제 이 페이지에 있는 데이터를 받을 수 있는지 확인해봅시다.

 

[code]

$ go run .

[/code]

 

1030332716_1675670586.323.png

 

이제 POST /crawl 라우트를 만들어봅시다.

기존에는 /app.go 에서 라우트를 설정했지만 이제 확장성을 위해 분리해봅시다.

 

/internal/rotues/public_route.go

[code]

package routes

 

import (

    "github.com/gofiber/fiber/v2"

)

 

func PublicRoutes(app *fiber.App) {

    app.Get("/crawl", func(c *fiber.Ctx) error {

        return c.Render("crawl", fiber.Map{})

    })

 

    app.Post("/crawl", func(c *fiber.Ctx) error {

        return c.SendString(c.FormValue("regex_url"))

    })

}

[/code]

 

정상 작동하게 된다면 목록페이지 정규표현식에 입력한 값이 출력됩니다.

 

1030332716_1675670803.5267.png

 

작동하네요.

 

이제 컨트롤러를 등록해서 수집 테스트를 해봅시다.

web_controller.go -> 웹에서 데이터를 받고, 해당 데이터를 crawl_controller.go로 넘깁니다.

crawl_controller.go -> 넘겨받은 데이터를 이용해 수집합니다.

 

/app/controllers/web_controller.go

[code]

package controllers

 

import (

    "fmt"

    "github.com/gofiber/fiber/v2"

)

 

func PageCrawl(c *fiber.Ctx) error {

    return c.Render("crawl", fiber.Map{})

}

 

func Crawl(c *fiber.Ctx) error {

    url := c.FormValue("url") // 목록 페이지 URL

 

    reg := make(map[string]string) // 정규표현식 Map

    reg["url"] = c.FormValue("regex_url")

    reg["subject"] = c.FormValue("regex_subject")

    reg["content"] = c.FormValue("regex_content")

 

    result, err := crawl(url, reg)

    if err != nil {

        return c.SendString(err.Error()) // 에러 발생 시 에러 반환

    }

 

    return c.SendString(fmt.Sprintf("%v", result))

}

[/code]

 

/app/controllers/crawl_controller.go

[code]

package controllers

 

import (

    "regexp"

    "strconv"

    "strings"

 

    "github.com/go-resty/resty/v2"

)

 

func crawl(url string, reg map[string]string) ([]string, error) {

    client := resty.New()

    url = strings.Split(url, ":page:")[0] // 목록 페이지 url에서 :page: 부분을 제거

 

    result, err := boardCrawl(client, url, reg["url"])

    if err != nil {

        return result, err

    }

 

    return result, nil

}

 

func boardCrawl(client *resty.Client, url string, regex string) ([]string, error) {

    urlResult := make([]string, 0)

 

    for i := 1; ; i++ {

        // 페이지 번호 붙이기

        strIndex := strconv.Itoa(i)

        resp, err := client.R().Get(url + strIndex)

        if err != nil {

            return urlResult, err

        }

 

        regex = `(?m)` + regex

 

        reg, err := regexp.Complie(regex)

        if err != nil { // 정규표현식에서 에러날 경우 에러 반환

            return urlResult, err

        }

 

        if len(reg.FindString(resp.String())) == 0 {

            break // 정규표현식에서 검출된 게 없을 때 벗어나기

        }

 

        for _, match := range reg.FindAllString(resp.String(), -1) {

            urlStr := strings.ReplaceAll(reg.FindStringSubmatch(match)[1], "&amp;", "&")

            urlResult = append(urlResult, urlStr)

        }

    }

 

    return urlResult, nil

}

[/code]

 

이제 해당 컨트롤러가 작동이 될 수 있도록 라우트를 수정해야 합니다.

 

/internal/routes/public_route.go

[code]

package routes

 

import (

    "example/crawler/app/controllers"

    "github.com/gofiber/fiber/v2"

)

 

func PublicRoutes(app *fiber.App) {

    app.Get("/crawl", controllers.PageCrawl)

    app.Post("/crawl", controllers.Crawl)

}

[/code]

 

이 라우트 내용이 적용되어야 하므로 app.go 를 수정합시다.

 

/app.go

[code]

package main

 

import (

    "example/crawler/internal/configs"

    "example/crawler/internal/routes"

    "github.com/gofiber/fiber/v2"

)

 

func main() {

    app := fiber.New(configs.FiberConfig())

    routes.PublicRotues(app)

 

    app.Listen(":3000")

}

[/code]

 

그럼 이제 테스트를 해봅시다./

 

터미널

[code]

$ go mod tidy

$ go run .

[/code]

 

1030332716_1675672845.5553.png

 

URL 부분에 page 번호가 들어가는 부분에 :page:를 넣고, 정규표현식도 입력해서 실행한다면

 

1030332716_1675672888.583.png

 

짜란..

 

1030332716_1675672939.7175.png

약 202개의 목록 페이지를 가져오는데 900ms 가 나오네요.

|

댓글 작성

댓글을 작성하시려면 로그인이 필요합니다.

로그인하기
🐛 버그신고