后台
This commit is contained in:
parent
0c0458137e
commit
3eb54a8c25
187
main.go
187
main.go
|
@ -6,26 +6,44 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fetchData struct {
|
type fetchData struct {
|
||||||
url string
|
Url string `json:"url"`
|
||||||
title string
|
Title string `json:"title"`
|
||||||
desc string
|
Desc string `json:"desc"`
|
||||||
date string
|
Date string `json:"date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type connChan struct {
|
||||||
|
conn string
|
||||||
|
msg message
|
||||||
|
}
|
||||||
|
type dataChan struct {
|
||||||
|
conn string
|
||||||
|
item []fetchData
|
||||||
|
}
|
||||||
|
|
||||||
type fetchHandler struct {
|
type fetchHandler struct {
|
||||||
fetchUrl string
|
fetchUrl string
|
||||||
hadFetchData []fetchData
|
hadFetchData []fetchData
|
||||||
cronTime time.Duration
|
cronTime map[string]time.Duration
|
||||||
keyword string
|
keyword map[string]string
|
||||||
hadFetchedMap map[string]int
|
hadFetchedMap map[string]int
|
||||||
reloadCron chan int
|
reloadCron map[string]chan int
|
||||||
isOff chan int
|
isOff chan int
|
||||||
ws *websocket.Conn
|
rMsgChan chan connChan
|
||||||
rMsgChan chan message
|
newFetchItem chan dataChan
|
||||||
newFetchItem chan []fetchData
|
connMap map[string]*websocket.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type setting struct {
|
||||||
|
Keyword string `json:"keyword"`
|
||||||
|
TimeStep int `json:"timeStep"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type message struct {
|
type message struct {
|
||||||
|
@ -35,39 +53,53 @@ type message struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFetchHandler(fetchUrl, keyword string) *fetchHandler {
|
func newFetchHandler(fetchUrl string) *fetchHandler {
|
||||||
return &fetchHandler{
|
return &fetchHandler{
|
||||||
fetchUrl: fetchUrl,
|
fetchUrl: fetchUrl,
|
||||||
keyword: keyword,
|
keyword: make(map[string]string),
|
||||||
hadFetchedMap: make(map[string]int),
|
hadFetchedMap: make(map[string]int),
|
||||||
cronTime: 60 * time.Second,
|
cronTime: make(map[string]time.Duration),
|
||||||
reloadCron: make(chan int),
|
reloadCron: make(map[string]chan int),
|
||||||
isOff: make(chan int),
|
isOff: make(chan int),
|
||||||
rMsgChan: make(chan message, 10),
|
rMsgChan: make(chan connChan, 10),
|
||||||
newFetchItem: make(chan []fetchData, 10),
|
newFetchItem: make(chan dataChan, 10),
|
||||||
|
connMap: make(map[string]*websocket.Conn),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fetchHandler) handle() {
|
func (f *fetchHandler) handle(conn string) {
|
||||||
f.parsesDom(f.fetch(f.fetchUrl + f.keyword))
|
key := "纪检"
|
||||||
|
if kk, ok := f.keyword[conn]; ok && kk != "" {
|
||||||
|
key = kk
|
||||||
|
}
|
||||||
|
f.parsesDom(f.fetch(f.fetchUrl+key), conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fetchHandler) receiveMsg() {
|
func (f *fetchHandler) receiveMsg() {
|
||||||
for {
|
for {
|
||||||
r := <-f.rMsgChan
|
r := <-f.rMsgChan
|
||||||
switch r.Action {
|
switch r.msg.Action {
|
||||||
case "search":
|
case "search":
|
||||||
f.handle()
|
if t, ok := r.msg.Data.(*setting); ok {
|
||||||
case "timeStepSet":
|
f.reloadCron[r.conn] <- t.TimeStep
|
||||||
if t, ok := r.Data.(int); ok {
|
f.keyword[r.conn] = t.Keyword
|
||||||
f.reloadCron <- t
|
f.handle(r.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "timeStepSet":
|
||||||
|
if t, ok := r.msg.Data.(int); ok {
|
||||||
|
f.reloadCron[r.conn] <- t
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fetchHandler) fetch(url string) *http.Response {
|
func (f *fetchHandler) fetch(url string) *http.Response {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
client := http.Client{
|
client := http.Client{
|
||||||
Transport: nil,
|
Transport: nil,
|
||||||
CheckRedirect: nil,
|
CheckRedirect: nil,
|
||||||
|
@ -94,33 +126,55 @@ func (f *fetchHandler) fetch(url string) *http.Response {
|
||||||
req.Header.Add("postman-token", "81407fbc-2b96-54a7-0193-f640156714ab")
|
req.Header.Add("postman-token", "81407fbc-2b96-54a7-0193-f640156714ab")
|
||||||
|
|
||||||
response, err := client.Do(req)
|
response, err := client.Do(req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fetchHandler) parsesDom(html *http.Response) {
|
func (f *fetchHandler) parsesDom(html *http.Response, conn string) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
doc, err := goquery.NewDocumentFromReader(html.Body)
|
doc, err := goquery.NewDocumentFromReader(html.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
var newFetch []fetchData
|
||||||
|
ti := time.Now()
|
||||||
|
compile := regexp.MustCompile(`(\d+)`)
|
||||||
|
|
||||||
doc.Find("div[class=\"result-op c-container xpath-log new-pmd\"]").Each(func(i int, selection *goquery.Selection) {
|
doc.Find("div[class=\"result-op c-container xpath-log new-pmd\"]").Each(func(i int, selection *goquery.Selection) {
|
||||||
data := fetchData{}
|
data := fetchData{}
|
||||||
data.url, _ = selection.Attr("mu")
|
data.Url, _ = selection.Attr("mu")
|
||||||
t := selection.Find(".news-title-font_1xS-F").First()
|
t := selection.Find(".news-title-font_1xS-F").First()
|
||||||
data.title = t.Text()
|
data.Title = t.Text()
|
||||||
data.desc = selection.Find(".c-row .c-color-text").First().Text()
|
data.Desc = selection.Find(".c-row .c-color-text").First().Text()
|
||||||
k := data.url + "_" + data.title
|
data.Date = selection.Find("span[class=\"c-color-gray2 c-font-normal c-gap-right-xsmall\"]").First().Text()
|
||||||
var newFetch []fetchData
|
n := compile.FindAllStringSubmatch(data.Date, -1)
|
||||||
|
nn, _ := strconv.Atoi(n[0][0])
|
||||||
|
if strings.Contains(data.Date, "小时") {
|
||||||
|
data.Date = ti.Add(-time.Duration(nn) * time.Hour).Format("2006-01-02 15:04")
|
||||||
|
}
|
||||||
|
if strings.Contains(data.Date, "分钟") {
|
||||||
|
data.Date = ti.Add(-time.Duration(nn) * time.Minute).Format("2006-01-02 15:04")
|
||||||
|
}
|
||||||
|
k := conn + "_" + data.Url + "_" + data.Title
|
||||||
if _, ok := f.hadFetchedMap[k]; !ok {
|
if _, ok := f.hadFetchedMap[k]; !ok {
|
||||||
f.hadFetchData = append(f.hadFetchData, data)
|
f.hadFetchData = append(f.hadFetchData, data)
|
||||||
f.hadFetchedMap[k] = 1
|
f.hadFetchedMap[k] = 1
|
||||||
newFetch = append(newFetch, data)
|
newFetch = append(newFetch, data)
|
||||||
}
|
}
|
||||||
f.newFetchItem <- newFetch
|
|
||||||
})
|
})
|
||||||
|
if len(newFetch) > 0 {
|
||||||
|
f.newFetchItem <- dataChan{
|
||||||
|
conn: conn,
|
||||||
|
item: newFetch,
|
||||||
|
}
|
||||||
|
}
|
||||||
err = html.Body.Close()
|
err = html.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -130,11 +184,12 @@ func (f *fetchHandler) parsesDom(html *http.Response) {
|
||||||
func (f *fetchHandler) sendFetchData() {
|
func (f *fetchHandler) sendFetchData() {
|
||||||
for {
|
for {
|
||||||
data := <-f.newFetchItem
|
data := <-f.newFetchItem
|
||||||
err := f.ws.WriteJSON(message{
|
|
||||||
|
err := f.connMap[data.conn].WriteJSON(message{
|
||||||
Status: true,
|
Status: true,
|
||||||
Action: "newData",
|
Action: "newData",
|
||||||
Message: "",
|
Message: "",
|
||||||
Data: data,
|
Data: data.item,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -142,34 +197,46 @@ func (f *fetchHandler) sendFetchData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fetchHandler) cronFetch() {
|
func (f *fetchHandler) cronFetch(conn string, c chan int) {
|
||||||
t := time.NewTicker(f.cronTime)
|
step, ok := f.cronTime[conn]
|
||||||
|
if !ok {
|
||||||
|
step = time.Second * 60
|
||||||
|
}
|
||||||
|
t := time.NewTicker(step)
|
||||||
|
if _, ok := f.cronTime[conn]; !ok {
|
||||||
|
f.reloadCron[conn] = make(chan int)
|
||||||
|
}
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
f.handle()
|
f.handle(conn)
|
||||||
case tt := <-f.reloadCron:
|
case tt := <-f.reloadCron[conn]:
|
||||||
f.cronTime = time.Duration(tt) * time.Second
|
f.cronTime[conn] = time.Duration(tt) * time.Second
|
||||||
go f.cronFetch()
|
go f.cronFetch(conn, c)
|
||||||
return
|
return
|
||||||
case <-f.isOff:
|
case <-c:
|
||||||
|
close(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
h := newFetchHandler("https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word=", "纪检")
|
h := newFetchHandler("https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word=")
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
var upgrader = websocket.Upgrader{}
|
var upgrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
go h.sendFetchData()
|
||||||
|
go h.receiveMsg()
|
||||||
router.LoadHTMLGlob("templates/*")
|
router.LoadHTMLGlob("templates/*")
|
||||||
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
|
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
|
||||||
router.GET("/index", func(c *gin.Context) {
|
router.GET("/index", func(c *gin.Context) {
|
||||||
c.HTML(http.StatusOK, "index.gohtml", gin.H{
|
c.HTML(http.StatusOK, "index.gohtml", gin.H{
|
||||||
"title": "爬虫",
|
"title": "爬虫",
|
||||||
"keyword": h.keyword,
|
|
||||||
"timeStep": h.cronTime.Seconds(),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
router.GET("ws", func(c *gin.Context) {
|
router.GET("ws", func(c *gin.Context) {
|
||||||
|
@ -181,17 +248,39 @@ func main() {
|
||||||
Data: nil,
|
Data: nil,
|
||||||
Action: "upgradeWs",
|
Action: "upgradeWs",
|
||||||
})
|
})
|
||||||
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.ws = conn
|
remote := conn.RemoteAddr().String()
|
||||||
msg := message{}
|
if _, ok := h.connMap[remote]; !ok {
|
||||||
|
h.connMap[remote] = conn
|
||||||
|
}
|
||||||
|
cc := make(chan int)
|
||||||
|
go h.cronFetch(remote, cc)
|
||||||
|
go func() {
|
||||||
|
msg := connChan{
|
||||||
|
conn: remote,
|
||||||
|
msg: message{
|
||||||
|
Data: &setting{},
|
||||||
|
},
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
err := conn.ReadJSON(msg)
|
err := conn.ReadJSON(&msg.msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if !websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
||||||
|
delete(h.connMap, remote)
|
||||||
|
cc <- 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
h.rMsgChan <- msg
|
h.rMsgChan <- msg
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
router.Run(":8080")
|
}()
|
||||||
|
})
|
||||||
|
err := router.Run(":8080")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user