golang使用walk编写的博客搜索查看的windows下的GUI软件

zzxfreeman · · 1307 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

为了学习golang,我使用了golang walk这个windows下的GUI包实现了一款博客搜索查看的小软件。

先上个展示图

输入图片说明 输入图片说明

实现了几个功能

  1. 可以查询五个博客网站 2.可以翻页 3.有收藏功能
// Copyright 2012 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/lxn/walk"
	"github.com/russross/blackfriday"

	. "github.com/lxn/walk/declarative"
)

func main() {

	//main
	mw := &MyMainWindow{}

	if err := (MainWindow{
		Icon:     "img/search.ico",
		AssignTo: &mw.MainWindow,
		Title:    "BolgSearch -- by tim_zhang",

		MenuItems: []MenuItem{
			Menu{
				Text: "&编辑",
				Items: []MenuItem{
					Separator{},
					Action{
						Text:        "退出",
						OnTriggered: func() { mw.Close() },
					},
				},
			},
			Menu{
				Text: "&收藏",
				Items: []MenuItem{
					Separator{},
					Action{
						Text:        "查看",
						OnTriggered: mw.search,
					},
				},
			},
			Menu{
				Text: "&帮助",
				Items: []MenuItem{
					Action{
						Text:        "关于",
						OnTriggered: mw.aboutAction_Triggered,
					},
				},
			},
		},
		MinSize: Size{1000, 600},
		Layout:  VBox{MarginsZero: true},

		Children: []Widget{
			Composite{

				MaxSize: Size{0, 50},
				Layout:  HBox{},
				Children: []Widget{
					PushButton{
						AssignTo: &mw.favorites,
						Text:     "收藏",
					},
					PushButton{
						AssignTo: &mw.unfavorites,
						Text:     "取消收藏",
					},
					Label{Text: "网站: "},
					RadioButtonGroup{

						DataMember: "Web",
						Buttons: []RadioButton{
							RadioButton{
								Name:     "all",
								Text:     "全部",
								Value:    "1",
								AssignTo: &mw.all,
							},
							RadioButton{
								Name:     "jianshu",
								Text:     "简书",
								Value:    "2",
								AssignTo: &mw.jianshu,
							},
							RadioButton{
								Name:     "juejin",
								Text:     "掘金",
								Value:    "3",
								AssignTo: &mw.juejin,
							},
							RadioButton{
								Name:     "bokeyuan",
								Text:     "博客园",
								Value:    "4",
								AssignTo: &mw.bokeyuan,
							},
							RadioButton{
								Name:     "csdn",
								Text:     "CSDN",
								Value:    "5",
								AssignTo: &mw.csdn,
							},
							RadioButton{
								Name:     "oschina",
								Text:     "OSCHINA",
								Value:    "6",
								AssignTo: &mw.os,
							},
						},
					},
					Label{Text: "关键词: "},
					LineEdit{
						AssignTo: &mw.keywords,
						Text:     "golang",
					},
					PushButton{
						AssignTo: &mw.query,
						Text:     "查询",
					},
					PushButton{
						AssignTo: &mw.nextquery,
						Text:     "下一页",
					},
					PushButton{
						AssignTo: &mw.prvquery,
						Text:     "上一页",
					},
				},
			},

			Composite{
				Layout: Grid{Columns: 2, Spacing: 10},
				Children: []Widget{
					ListBox{
						MaxSize:               Size{200, 0},
						AssignTo:              &mw.lb,
						OnCurrentIndexChanged: mw.lb_CurrentIndexChanged,
						OnItemActivated:       mw.lb_ItemActivated,
					},

					WebView{
						//MinSize:  Size{1000, 0},
						AssignTo: &mw.wv,
					},
				},
			},
		},
	}.Create()); err != nil {
		log.Fatal(err)
	}

	mw.query.Clicked().Attach(func() {
		go func() {

			mw.GetList(1)

		}()
	})

	mw.nextquery.Clicked().Attach(func() {
		go func() {

			mw.page = mw.page + 1
			mw.GetList(mw.page)

		}()
	})

	mw.prvquery.Clicked().Attach(func() {
		go func() {
			mw.page = mw.page - 1
			if mw.page == 0 {
				mw.page = 1
			}

			mw.GetList(mw.page)

		}()
	})

	mw.favorites.Clicked().Attach(func() {
		go func() {
			mw.addFavorite()
			mw.favorites.SetEnabled(false)
			mw.unfavorites.SetEnabled(true)
			walk.MsgBox(mw, "提示", "收藏成功", walk.MsgBoxIconInformation)
		}()
	})

	mw.unfavorites.Clicked().Attach(func() {
		go func() {
			mw.delFavorite()
			mw.favorites.SetEnabled(true)
			mw.unfavorites.SetEnabled(false)
			walk.MsgBox(mw, "提示", "取消收藏", walk.MsgBoxIconWarning)

		}()
	})

	//初始化
	mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/init.html")
	mw.all.SetChecked(true)
	mw.favorites.SetEnabled(false)
	mw.unfavorites.SetEnabled(false)
	mw.curtitle = ""
	mw.cururl = ""
	mw.Run()
}

type MyMainWindow struct {
	*walk.MainWindow
	lb          *walk.ListBox
	te          *walk.TextEdit
	wv          *walk.WebView
	all         *walk.RadioButton
	jianshu     *walk.RadioButton
	juejin      *walk.RadioButton
	bokeyuan    *walk.RadioButton
	csdn        *walk.RadioButton
	os          *walk.RadioButton
	keywords    *walk.LineEdit
	model       *Model
	query       *walk.PushButton
	nextquery   *walk.PushButton
	prvquery    *walk.PushButton
	favorites   *walk.PushButton
	unfavorites *walk.PushButton
	page        int
	curtitle    string
	cururl      string
}

type JianshuList struct {
	Q          string `json:"q"`
	Page       int    `json:"page"`
	Type       string `json:"type"`
	TotalCount int    `json:"total_count"`
	PerPage    int    `json:"per_page"`
	TotalPages int    `json:"total_pages"`
	OrderBy    string `json:"order_by"`
	Entries    []struct {
		ID      int    `json:"id"`
		Title   string `json:"title"`
		Slug    string `json:"slug"`
		Content string `json:"content"`
		User    struct {
			ID        int    `json:"id"`
			Nickname  string `json:"nickname"`
			Slug      string `json:"slug"`
			AvatarURL string `json:"avatar_url"`
		} `json:"user"`
		Notebook struct {
			ID   int    `json:"id"`
			Name string `json:"name"`
		} `json:"notebook"`
		Commentable         bool      `json:"commentable"`
		PublicCommentsCount int       `json:"public_comments_count"`
		LikesCount          int       `json:"likes_count"`
		ViewsCount          int       `json:"views_count"`
		TotalRewardsCount   int       `json:"total_rewards_count"`
		FirstSharedAt       time.Time `json:"first_shared_at"`
	} `json:"entries"`
	RelatedUsers []struct {
		ID              int    `json:"id"`
		AvatarURL       string `json:"avatar_url"`
		Nickname        string `json:"nickname"`
		Slug            string `json:"slug"`
		TotalWordage    int    `json:"total_wordage"`
		TotalLikesCount int    `json:"total_likes_count"`
	} `json:"related_users"`
	MoreRelatedUsers   bool `json:"more_related_users"`
	RelatedCollections []struct {
		ID               int    `json:"id"`
		Title            string `json:"title"`
		Slug             string `json:"slug"`
		ImageURL         string `json:"image_url"`
		PublicNotesCount int    `json:"public_notes_count"`
		LikesCount       int    `json:"likes_count"`
	} `json:"related_collections"`
	MoreRelatedCollections bool `json:"more_related_collections"`
}

type JuejinList struct {
	D []struct {
		CollectionCount int    `json:"collectionCount"`
		OriginalURL     string `json:"originalUrl"`
		CommentsCount   int    `json:"commentsCount"`
		User            struct {
			ObjectID string `json:"objectId"`
			JobTitle string `json:"jobTitle"`
			Username string `json:"username"`
		} `json:"user"`
		ObjectID  string        `json:"objectId"`
		Content   string        `json:"content"`
		Title     string        `json:"title"`
		CreatedAt time.Time     `json:"createdAt"`
		Tags      []interface{} `json:"tags"`
		UpdatedAt time.Time     `json:"updatedAt"`
	} `json:"d"`
	M string `json:"m"`
	S int    `json:"s"`
}

type Item struct {
	name  string
	value string
}

type Items struct {
	items []Item
}

type Model struct {
	walk.ListModelBase
	items []Item
}

func (m *Model) ItemCount() int {
	return len(m.items)
}

func (m *Model) Value(index int) interface{} {
	return m.items[index].name
}

func (mw *MyMainWindow) aboutAction_Triggered() {
	walk.MsgBox(mw, "关于", "BlogSearch阅读器v1.0\n作者:tim_zhang 完成时间:2017-8-25 日", walk.MsgBoxIconQuestion)
}

func (mw *MyMainWindow) search() {
	mw.GetList(-999)
}

func (mw *MyMainWindow) GetList(page int) {
	mw.page = page
	keywords := mw.keywords.Text()
	enkeywords := url.QueryEscape(keywords)
	//mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/init.html")
	defer func() {
		mw.lb.SetCurrentIndex(-1)

	}()
	if page == -999 {
		go func() {
			rf := mw.readFavorite()
			m := &Model{items: rf.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.all.Checked() == true {
		go func() {
			jianshu := getjianshList(enkeywords, strconv.Itoa(page))
			juejin := getjuejinList(enkeywords, strconv.Itoa(page))
			bokeyuan := getbokeyuanList(enkeywords, strconv.Itoa(page))
			csdn := getcsdnList(enkeywords, strconv.Itoa(page))
			os := getosList(enkeywords, strconv.Itoa(page))
			var k = 0
			var lens = 0
			if len(jianshu.items) > 0 {
				lens += len(jianshu.items)
			}
			if len(juejin.items) > 0 {
				lens += len(juejin.items)
			}
			if len(bokeyuan.items) > 0 {
				lens += len(bokeyuan.items)
			}
			if len(csdn.items) > 0 {
				lens += len(csdn.items)
			}
			if len(os.items) > 0 {
				lens += len(os.items)
			}
			m := &Model{items: make([]Item, lens)}

			if len(jianshu.items) > 0 {

				for _, jian := range jianshu.items {
					m.items[k] = jian
					k++
				}
			}
			if len(juejin.items) > 0 {

				for _, jue := range juejin.items {
					m.items[k] = jue
					k++
				}
			}
			if len(bokeyuan.items) > 0 {

				for _, bo := range bokeyuan.items {
					m.items[k] = bo
					k++
				}
			}
			if len(csdn.items) > 0 {

				for _, cs := range csdn.items {
					m.items[k] = cs
					k++
				}
			}
			if len(os.items) > 0 {

				for _, osl := range os.items {
					m.items[k] = osl
					k++
				}
			}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.jianshu.Checked() == true {
		go func() {
			jianshu := getjianshList(enkeywords, strconv.Itoa(page))
			m := &Model{items: jianshu.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.juejin.Checked() == true {
		go func() {
			juejin := getjuejinList(enkeywords, strconv.Itoa(page))
			m := &Model{items: juejin.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.bokeyuan.Checked() == true {
		go func() {
			bokeyuan := getbokeyuanList(enkeywords, strconv.Itoa(page))
			m := &Model{items: bokeyuan.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.csdn.Checked() == true {
		go func() {
			csdn := getcsdnList(enkeywords, strconv.Itoa(page))
			m := &Model{items: csdn.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}
	if mw.os.Checked() == true {
		go func() {
			os := getosList(enkeywords, strconv.Itoa(page))
			m := &Model{items: os.items}
			mw.lb.SetModel(m)
			mw.model = m
		}()
		return
	}

	return
}

func (mw *MyMainWindow) lb_CurrentIndexChanged() {

	i := mw.lb.CurrentIndex()
	if i < 0 {
		return
	}
	//defer mw.lb.SetCurrentIndex(-1)
	item := &mw.model.items[i]
	s := strings.Split(item.value, "|")
	if len(s) == 2 {
		switch s[0] {
		case "jianshu":
			mw.getjianshu(item.name, s[1])
		case "juejin":
			mw.getjuejin(item.name, s[1])
		case "bokeyuan":
			mw.getbokeyuan(item.name, s[1])
		case "csdn":
			mw.getcsdn(item.name, s[1])
		case "os":
			mw.getos(item.name, s[1])
		}
		//记录当前页面的标题和链接
		mw.curtitle = item.name
		mw.cururl = item.value
		if mw.checkFavorite() {
			mw.favorites.SetEnabled(false)
			mw.unfavorites.SetEnabled(true)
		} else {
			mw.favorites.SetEnabled(true)
			mw.unfavorites.SetEnabled(false)
		}
	} else {
		mw.curtitle = ""
		mw.cururl = ""
		mw.favorites.SetEnabled(false)
		mw.unfavorites.SetEnabled(false)
		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}

	return
}

func (mw *MyMainWindow) lb_ItemActivated() {
	mw.curtitle = ""
	mw.cururl = ""
	mw.favorites.SetEnabled(false)
	mw.unfavorites.SetEnabled(false)
	mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
}

func (mw *MyMainWindow) getjianshu(name string, value string) {
	go func() {
		re, _ := regexp.Compile("<img[\\S\\s]+?>")
		userFile := "data/xxx.html"
		fout, err := os.Create(userFile)
		defer fout.Close()
		if err != nil {

			return
		}
		//walk.MsgBox(mw, "查询", "http://www.jianshu.com/p/"+value, walk.MsgBoxIconInformation)
		doc, err := goquery.NewDocument("http://www.jianshu.com/p/" + value)
		if err != nil {
			fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————简书</h3><a href='http://www.jianshu.com/p/" + value + "' target='_blank'>文章地址</a>")
		}
		ht, _ := doc.Find(".show-content").Html()

		fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————简书</h3><a href='http://www.jianshu.com/p/" + value + "' target='_blank'>文章地址</a>" + re.ReplaceAllString(ht, ""))

		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}()

}

func (mw *MyMainWindow) getjuejin(name string, value string) {
	go func() {
		userFile := "data/xxx.html"
		fout, err := os.Create(userFile)
		defer fout.Close()
		if err != nil {
			return
		}
		//walk.MsgBox(mw, "查询", "https://juejin.im/entry/"+value, walk.MsgBoxIconInformation)
		doc, err := goquery.NewDocument("https://juejin.im/entry/" + value)
		if err != nil {
			//log.Fatal(err)
			fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + " ————掘金</h3><a href='https://juejin.im/entry/" + value + "' target='_blank'>文章地址</a>")
		}
		ht, _ := doc.Find(".entry-content").Html()
		re, _ := regexp.Compile("<img[\\S\\s]+?>")

		fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————掘金</h3><a href='https://juejin.im/entry/" + value + "' target='_blank'>文章地址</a>" + re.ReplaceAllString(ht, ""))
		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}()

}

func (mw *MyMainWindow) getbokeyuan(name string, value string) {
	go func() {
		userFile := "data/xxx.html"
		fout, err := os.Create(userFile)
		defer fout.Close()
		if err != nil {
			return
		}
		//walk.MsgBox(mw, "查询", value, walk.MsgBoxIconInformation)
		doc, err := goquery.NewDocument(value)
		if err != nil {
			//log.Fatal(err)
			fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + " ————博客园</h3><a href='" + value + "' target='_blank'>文章地址</a>")
		}
		ht, _ := doc.Find("#cnblogs_post_body").Html()
		re, _ := regexp.Compile("<img[\\S\\s]+?>")

		fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————博客园</h3><a href='" + value + "' target='_blank'>文章地址</a>" + re.ReplaceAllString(ht, ""))
		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}()

}

func (mw *MyMainWindow) getcsdn(name string, value string) {
	go func() {
		userFile := "data/xxx.html"
		fout, err := os.Create(userFile)
		defer fout.Close()
		if err != nil {
			return
		}
		//walk.MsgBox(mw, "查询", value, walk.MsgBoxIconInformation)
		doc, err := goquery.NewDocument(value)
		if err != nil {
			//log.Fatal(err)
			fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + " ————CSDN</h3><a href='" + value + "' target='_blank'>文章地址</a>")
		}
		ht, _ := doc.Find("#article_content").Html()
		re, _ := regexp.Compile("<img[\\S\\s]+?>")
		hs := re.ReplaceAllString(ht, "")
		res, _ := regexp.Compile("<script[\\S\\s]+?>")

		fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————CSDN</h3><a href='" + value + "' target='_blank'>文章地址</a>" + res.ReplaceAllString(hs, ""))
		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}()

}

func (mw *MyMainWindow) getos(name string, value string) {
	go func() {
		userFile := "data/xxx.html"
		fout, err := os.Create(userFile)
		defer fout.Close()
		if err != nil {
			return
		}
		//walk.MsgBox(mw, "查询", value, walk.MsgBoxIconInformation)
		doc, err := goquery.NewDocument(value)
		if err != nil {
			//log.Fatal(err)
			fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + " ————OSCHINA</h3><a href='" + value + "' target='_blank'>文章地址</a>")
		}
		ht, _ := doc.Find(".blog-body").Html()
		hs, _ := doc.Find(".noshow_content").Html()
		if len(hs) != 0 {
			ht = string(blackfriday.MarkdownBasic([]byte(hs)))

		}
		re, _ := regexp.Compile("<img[\\S\\s]+?>")

		fout.WriteString("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><h3>" + name + "————OSCHINA</h3><a href='" + value + "' target='_blank'>文章地址</a>" + re.ReplaceAllString(ht, ""))
		mw.wv.SetURL("file:///" + getCurrentDirectory() + "/data/xxx.html")
	}()
}

func httpDo(method string, url string) (bodys string) {
	client := &http.Client{}

	req, err := http.NewRequest(method, url, nil)
	if err != nil {

	}

	if method == "POST" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	} else {
		req.Header.Set("Accept", "application/json")
	}
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")
	resp, err := client.Do(req)

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	bodys = string(body)

	if err != nil {
		// handle error
		return ""
	}

	// fmt.Println(string(body))
	return bodys
}

func (mw *MyMainWindow) addFavorite() {
	mw.delFavorite()
	rf := mw.readFavorite()
	st := mw.curtitle + "<$>" + mw.cururl + "$$"
	for i, ite := range rf.items {
		if i == len(rf.items)-1 {

			st = st + ite.name + "<$>" + ite.value + "$$"
		} else {
			st = st + ite.name + "<$>" + ite.value

		}
	}

	userFile := "data/favorite"
	fout, err := os.Create(userFile)
	defer fout.Close()
	if err != nil {
		return
	}
	fout.WriteString(st)
}

func (mw *MyMainWindow) delFavorite() {

	rf := mw.readFavorite()
	sb := mw.curtitle + "<$>" + mw.cururl
	st := ""
	for i, ite := range rf.items {
		if sb != ite.name+"<$>"+ite.value {
			if i == 0 {
				st = st + ite.name + "<$>" + ite.value

			} else {

				st = st + "$$" + ite.name + "<$>" + ite.value
			}
		}
	}

	userFile := "data/favorite"
	fout, err := os.Create(userFile)
	defer fout.Close()
	if err != nil {
		return
	}
	fout.WriteString(st)
}

func (mw *MyMainWindow) readFavorite() Items {
	f, _ := os.Open("data/favorite")
	fd, _ := ioutil.ReadAll(f)
	fs := string(fd)
	s := strings.Split(fs, "$$")
	if len(s[0]) > 0 {
		data := Items{items: make([]Item, len(s))}
		for i, ite := range s {
			if len(ite) > 0 {
				b := strings.Split(ite, "<$>")
				data.items[i].name = b[0]
				data.items[i].value = b[1]
			}

		}
		return data
	} else {
		data := Items{}
		return data
	}
}

func (mw *MyMainWindow) checkFavorite() bool {
	rf := mw.readFavorite()
	sb := mw.curtitle + "<$>" + mw.cururl
	st := false
	for _, ite := range rf.items {
		if sb == ite.name+"<$>"+ite.value {
			st = true
		}
	}
	return st
}

func getjianshList(keywords string, page string) Items {
	body := httpDo("GET", "http://www.jianshu.com/search/do?q="+keywords+"&type=note&page="+page+"&order_by=default")
	var r JianshuList
	json.Unmarshal([]byte(body), &r)
	data := Items{items: make([]Item, len(r.Entries))}
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	for i, en := range r.Entries {
		data.items[i] = Item{re.ReplaceAllString(en.Title, ""), re.ReplaceAllString("jianshu|"+en.Slug, "")}
	}

	return data
}

func getjuejinList(keywords string, page string) Items {
	body := httpDo("GET", "https://search-merger-ms.juejin.im/v1/search?query="+keywords+"&page="+page+"&raw_result=false&src=web")
	var r JuejinList
	json.Unmarshal([]byte(body), &r)
	data := Items{items: make([]Item, len(r.D))}
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	for i, en := range r.D {
		data.items[i] = Item{re.ReplaceAllString(en.Title, ""), re.ReplaceAllString("juejin|"+en.ObjectID, "")}
	}

	return data
}

func getbokeyuanList(keywords string, page string) Items {
	data := Items{items: make([]Item, 15)}
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	doc, _ := goquery.NewDocument("http://zzk.cnblogs.com/s/blogpost?Keywords=" + keywords + "&pageindex=" + page)
	doc.Find(".searchItemTitle").Each(func(i int, s *goquery.Selection) {
		title := s.Text()
		value, _ := s.Find("a").Attr("href")
		data.items[i] = Item{strings.Replace(re.ReplaceAllString(title, ""), " ", "", -1), "bokeyuan|" + value}
	})
	return data
}

func getcsdnList(keywords string, page string) Items {
	data := Items{items: make([]Item, 10)}
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	doc, _ := goquery.NewDocument("http://so.csdn.net/so/search/s.do?p=" + page + "&q=" + keywords + "&t=blog&domain=&o=&s=&u=null&l=null&f=null")
	doc.Find(".search-list").Each(func(i int, s *goquery.Selection) {
		title := s.Find("a").Text()
		value, _ := s.Find("a").Attr("href")
		data.items[i] = Item{re.ReplaceAllString(title, ""), "csdn|" + value}
	})
	return data
}

func getosList(keywords string, page string) Items {
	data := Items{items: make([]Item, 20)}
	body := httpDo("GET", "https://www.oschina.net/search?scope=blog&sort_by_time=1&q="+keywords+"&p="+page)
	digitsRegexp := regexp.MustCompile(`"(.*)"`)
	s := digitsRegexp.FindStringSubmatch(body)
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	doc, _ := goquery.NewDocument("https://www.oschina.net/search" + s[1])
	doc.Find(".obj_type_3").Each(func(i int, s *goquery.Selection) {
		title := s.Find("a").Text()
		value, _ := s.Find("a").Attr("href")
		data.items[i] = Item{re.ReplaceAllString(title, ""), "os|" + value}
	})
	return data
}

func getCurrentDirectory() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}
	return strings.Replace(dir, "\\", "/", -1)
}

上面就是golang的代码。项目地址:BlogSearch

说说我遇到的一些坑。

1.walk这个项目非常好,不过例子很少。毕竟现在是移动开发的天下,桌面级应用少了很多,无奈。

2.walk中的webview很简陋js就不要想着运行了,我展示时候去掉了,不然会报错。

3.walk中的webview的图片显示到时没有太大问题,不过我展示时候还是去掉了,为什么请看下一条。

4.walk中的webview使用SetUrl改变了URL重新加载html后,如果加载未完成就重新Set的话程序会崩溃。   暂时没有找到合适的解决办法,这就是我去掉图片的原因加载图片慢,并且我看到walk的issue中有个提问是关于webview的内存不够也会导致程序崩溃,提问者提给golang官方,貌似还没有解决。

5.listbox 中 如果不加mw.lb.SetCurrentIndex(-1)也会导致重新更新list时候,程序崩溃

6.listbox中点击时候如果没有点击到item上也会崩溃。我的解决办法就是
i := mw.lb.CurrentIndex()
if i < 0 {
	return
}
其余就没有什么问题了。

walk我个人的感觉挺好的,只是缺乏一些好的复杂实例来学习研究,靠看源码进行开发这是个累人的办法/(ㄒoㄒ)/~~

最后说一句我只是为了学习golang开发了这款小软件,不做任何商业用途,也不会去破坏什么一个网站。希望大家理解:-D


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:zzxfreeman

查看原文:golang使用walk编写的博客搜索查看的windows下的GUI软件

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1307 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传