1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | package main import ( "bytes" "errors" "fmt" "math/rand" "net" "time" "github.com/geeksbaek/goinside" "github.com/xrash/smetrics" ) type Gallery struct { url string } type Article struct { subject string date time.Time ip net.IP } type Articles []*Article const ( maxDupSubjectCnt = 1 maxDupIPAddrCnt = 5 comparePageCnt = 10 ) func main() { start := time.Now() err := writeArticle(&Article{ subject: "제목", date: time.Now(), ip: _randIP(), }, &Gallery{ url: "http://gall.dcinside.com/board/lists/?id=programming", }) fmt.Println("validate duration :", time.Since(start)) fmt.Println("Error:", err) } func writeArticle(newArticle *Article, gall *Gallery) error { dupSubjectCnt, dupIPAddrCnt := 0, 0 for _, oldArticle := range readRecentlyArticles(gall) { if !isNearTime(newArticle, oldArticle) { continue } switch { case isDupSubject(newArticle, oldArticle): dupSubjectCnt++ case isDupIP(newArticle, oldArticle): dupIPAddrCnt++ } } switch { case maxDupSubjectCnt <= dupSubjectCnt: return errors.New("Over Maximum Subject Limit") case maxDupIPAddrCnt <= dupIPAddrCnt: return errors.New("Over Maximum IP Address Limit") } // doWrite(a) return nil } func readRecentlyArticles(gall *Gallery) (as Articles) { start := time.Now() for i := 1; i < comparePageCnt; i++ { list, err := goinside.GetList(gall.url, i) if err != nil { continue } for _, article := range list.Articles { as = append(as, &Article{ subject: article.Subject, date: *article.Date, ip: _randIP(), }) } } fmt.Println("recently article length :", len(as)) fmt.Println("fetch duration :", time.Since(start)) return } func isDupSubject(a, b *Article) bool { if smetrics.JaroWinkler(a.subject, b.subject, 0.7, 4) > 0.9 { return true } return false } func isNearTime(a, b *Article) bool { format := "2006/01/02 15:04" if a.date.Format(format) == b.date.Format(format) { return true } return false } func isDupIP(a, b *Article) bool { if bytes.Equal(a.ip, b.ip) { return true } return false } func _randIP() net.IP { rand.Seed(time.Now().UnixNano()) ipStr := fmt.Sprintf("%v.%v.%v.%v", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255)) return net.IP(ipStr) } | cs |
비교 대상은 글이 작성되는 게시판의 최근 글 10페이지
1. 분단위 동일한 시간에 글 제목에 대해 Jaro Winkler 알고리즘으로 90% 이상의 매칭도를 가지는 글이 1개 이상 있는 경우
2. 분단위 동일한 시간에 동일한 아이피가 5개 이상 있는 경우
너네가 게시판 운영자라면 어떤 알고리즘으로 필터링하고싶냐
댓글 0