Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery)

Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery)

体验 冒号搜索

1. 获取谷歌搜索api

谷歌搜索api教程html

2. 后台调用

程序入口 main.go前端

// goSearch project main.go
package main

import (
    "fmt"
    "net/http"
)

func main() {
    Api()
    ReadApi("./api.txt")
    go TimeTo()

    http.HandleFunc("/", Home)
    http.HandleFunc("/search", Search)
    http.Handle("/static", http.FileServer(http.Dir("./static")))

    fmt.Print("server is running\n")
    http.ListenAndServe(":80", nil)
}

处理函数 route.gojquery

// route
package main

import (
    "fmt"
    "io"
    "net/http"
    "strconv"
)

func Home(w http.ResponseWriter, r *http.Request) {
    fmt.Println("go")
    fmt.Println(GetBest())
    w.Write([]byte("hi"))
}

func Search(w http.ResponseWriter, r *http.Request) {
    url := "https://www.googleapis.com/customsearch/v1?cx=项目id&safe=是否开启安全模式(active)&key=" + GetBest()
    r.ParseForm()
    q := r.Form["q"][0]
    var p string
    var t string
    if r.Form["p"] != nil {
        p = r.Form["p"][0]
    } else {
        p = ""
    }
    if r.Form["t"] != nil {
        t = r.Form["t"][0]
    } else {
        t = ""
    }

    if q == "" {
        w.Write([]byte("null"))
        return
    } else {
        url = url + "&q=" + q
    }
    if p == "" {
        p = "1"
    } else {
        i, _ := strconv.Atoi(p)
        p = strconv.Itoa(i*10 + 1)
    }
    url = url + "&start=" + p

    if t != "" {
        url = url + "&siteSearch=" + t
    }

    fmt.Println("q= ", q, " p= ", p, " t= ", t)
    client := http.Client{}
    resp, err := client.Get(url)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    defer resp.Body.Close()
    w.Header().Set("Access-Control-Allow-Origin", "*")
    io.Copy(w, resp.Body)
}

多个api 获取使用次数最少api,从文件获取apis
api.gogolang

// api
package main

import (
    "bufio"
    "errors"
    "fmt"
    "os"
    "time"
)

type SeaApi struct {
    apis []api
    time time.Time
}

type api struct {
    apiCode string
    count   int
}

var apii *SeaApi
//初始化
func Api() {
    apii = &SeaApi{time: time.Now()}
}

func NewApi() *SeaApi {
    return &SeaApi{time: time.Now()}
}
//添加api
func AddApi(a string) {
    newApi := api{a, 0}
    apii.apis = append(apii.apis, newApi)
}

func (s *SeaApi) AddApi(a string) {
    newApi := api{a, 0}
    s.apis = append(s.apis, newApi)
}
//删除指定api
func DelApi(n int) {
    apii.apis = append(apii.apis[:n], apii.apis[n+1:]...)
}

func (s *SeaApi) DelApi(n int) {
    s.apis = append(s.apis[:n], s.apis[n+1:]...)
}
//获取指定api
func GetApi(n int) (api, error) {
    if n > len(apii.apis) {
        return api{}, errors.New("fault index")
    }
    return apii.apis[n], nil
}

func (s *SeaApi) GetApi(n int) (api, error) {
    if n > len(s.apis) {
        return api{}, errors.New("fault index")
    }
    return s.apis[n], nil
}
//获取全部api
func GetAllApi() *SeaApi {
    return apii
}

func (s *SeaApi) GetAllApi() *SeaApi {
    return s
}
//从文件读取api,每行一个,文件名api.txt
func ReadApi(file string) interface{} {
    f, err := os.Open(file)
    if err != nil {
        fmt.Print(err.Error())
        return nil
    }
    defer f.Close()
    Clear()
    scan := bufio.NewScanner(f)
    count := 0
    for scan.Scan() {
        str := scan.Text()
        apii.AddApi(str)
        count = count + 1
    }
    return count
}

func (s *SeaApi) ReadApi(file string) interface{} {
    f, err := os.Open(file)
    if err != nil {
        fmt.Print(err.Error())
        return nil
    }
    defer f.Close()
    Clear()
    scan := bufio.NewScanner(f)
    count := 0
    for scan.Scan() {
        str := scan.Text()
        s.AddApi(str)
        count = count + 1
    }
    return count
}
//清理全部api
func Clear() {
    apii.apis = apii.apis[0:0]
}

func (s *SeaApi) Clear() {
    s.apis = s.apis[0:0]
}

func TimeTo() {
    for {
        time.Sleep(time.Duration(1) * time.Hour)
        now := time.Now()
        if now.Sub(apii.time).Hours() > 24 {
            apii.time = now
            for _, a := range apii.apis {
                a.count = 0
            }
        }
    }
}
//轮询,满24小时更新使用次数为0
func (s *SeaApi) TimeTo() {
    for {
        time.Sleep(time.Duration(1) * time.Hour)
        now := time.Now()
        if now.Sub(s.time).Hours() > 24 {
            s.time = now
            for _, a := range s.apis {
                a.count = 0
            }
        }
    }
}

func GetBest() string {
    n := 0
    for i, a := range apii.apis {
        if apii.apis[n].count >= a.count {
            n = i
        }
    }
    apii.apis[n].count = apii.apis[n].count + 1
    return apii.apis[n].apiCode
}
//获取使用次数最少的api
func (s *SeaApi) GetBest() string {
    n := 0
    for i, a := range s.apis {
        if s.apis[n].count >= a.count {
            n = i
        }
    }
    s.apis[n].count = s.apis[n].count + 1
    return s.apis[n].apiCode
}

3. 前端页面

html能够本身设计ajax

主要js代码:json

index.jsbootstrap

$(document).ready(function () {
    //文本输入框监听
    $("#text").keydown(function (e) {
        var curKey = e.which;
        if (curKey == 13) {
            $("#go").click();
            return false;
        }
    });
    //搜索按钮监听
    $("#go").click(function () {
        var str = $("#text").val();
        console.log(str);
        if (str != '') window.location.href = 'search.html?q=' + str;
    });

    //判断是不是手机端
    function IsMobile() {
        var isMobile = {
            Android: function () {
                return navigator.userAgent.match(/Android/i) ? true : false;
            },
            BlackBerry: function () {
                return navigator.userAgent.match(/BlackBerry/i) ? true : false;
            },
            iOS: function () {
                return navigator.userAgent.match(/iPhone|iPad|iPod/i) ? true : false;
            },
            Windows: function () {
                return navigator.userAgent.match(/IEMobile/i) ? true : false;
            },
            any: function () {
                return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
            }
        };

        return isMobile.any(); //是移动设备
    }

    var mobile_flag = IsMobile();

    if (mobile_flag) {
        $("#mho").attr("style","font-size: 3em;");
        $("#pc1").hide();
    }
})

search.jsubuntu

$(document).ready(function () {
    var str = GetUrlPara();
    var nowPage = 0;
    $("#up").hide();
    $("#down").hide();
    //获取请求参数
    function GetUrlPara() {
        var url = document.location.toString();
        var arrUrl = url.split("?");
        var para = arrUrl[1];
        para = para.split("&");
        var p0 = para[0].split("=");
        return p0[1];
    }
    //ajax获取搜索值
    function Search(query, page, type) {
        query = decodeURIComponent(query);
        var urls = "后台服务器ip或域名/search?q=" + query + "&p=" + page + "&t=" + type;
        $("#tit").html("冒号--> " + decodeURIComponent(query));
        $("#text").attr("value", decodeURIComponent(query));
        urls = urls.replace(/[ ]/g,'_');
        console.log(urls);
        $.ajax({
            type: "GET",
            url: urls,
            dataType: "json",
            success: function (data) {
                $("#loading").hide();
                var str1 = '<div class="row"><div class="panel panel-default"><div class="panel-body"><p><h3><a href="';
                var str2 = '">';
                var str3 = '</a></h3></p><p>';
                var str4 = '</p><p><a href="';
                var str5 = '">';
                var str6 = '</a></p></div></div></div>';
                var all = '';
                for (var j = 0; j < data["items"].length; j++) {
                    all = all + str1 + data["items"][j]["link"] + str2 + data["items"][j]["title"] + str3 + data["items"][j]["snippet"] + str4 + data["items"][j]["link"] + str5 + data["items"][j]["displayLink"] + str6;
                }
                $("#cont").html(all);
                if (data["queries"]["nextPage"] != null) {
                    $("#down").show();
                } else {
                    $("#down").hide();
                }
                if (nowPage != 0) {
                    $("#up").show();
                } else {
                    $("#up").hide();
                }
            }
        });
    }

    Search(str, 0, "");

    $("#text").keydown(function (e) {
        var curKey = e.which;
        if (curKey == 13) {
            $("#go").click();
            return false;
        }
    });

    $("#go").click(function () {
        var strText = $("#text").val();
        if (strText == "") {
            window.location.href = 'index.html';
        }
        else {
            window.location.href = 'search.html?q=' + strText;
        }
        //Search(strText,0,"");
    });

    $("#logo").click(function () {
        window.location.href = 'index.html';
    });
    //回到顶部
    function pageScroll() {
        $('html,body').animate({
            scrollTop: 0
        }, 1000);
    }

    $("#up").click(function () {
        $("#loading").show();
        nowPage--;
        Search(str, nowPage, "");
        pageScroll();
    });

    $("#down").click(function () {
        $("#loading").show();
        nowPage++;
        Search(str, nowPage, "");
        pageScroll();
    });


    function IsMobile() {
        var isMobile = {
            Android: function () {
                return navigator.userAgent.match(/Android/i) ? true : false;
            },
            BlackBerry: function () {
                return navigator.userAgent.match(/BlackBerry/i) ? true : false;
            },
            iOS: function () {
                return navigator.userAgent.match(/iPhone|iPad|iPod/i) ? true : false;
            },
            Windows: function () {
                return navigator.userAgent.match(/IEMobile/i) ? true : false;
            },
            any: function () {
                return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
            }
        };

        return isMobile.any(); //是移动设备
    }

    var mobile_flag = IsMobile();

    if (mobile_flag) {
        $("#mho").attr("style", "font-size: 2em;text-align: center;");
    }
})

4. 程序上线

我将html、js托管在coding pages上,go程序发布到美国服务器ubuntu18上,服务器开启了bbr加速,域名所有使用cloudflare,并开启了cdn功能(有缓存,调试的话先关了)。api

小结

golang程序的编写,使用了许多go官方库,也踩了许多坑,可是对go 的库使用更加熟练。前端页面的编写主要用bootstrap和jquery框架,开发速度快不少,相较于之前,对这两个框架使用更加灵活,官方文档认真的看下来会发现之前没认真看真的走了好多弯路。缓存

效果图

首页

搜索页