字符界面与图形界面只能说各有优势。“老年人”比较喜迎字符界面:简单、轻巧,对电脑要求低,专注于内容。
考虑到爬电影通过命令行还是比较的反人类,想给它搭个简单的命令行界面。
tview库是golang下的界面库,完成基本的界面看来不是问题。
还是先HelloWorld
package main
import (
"github.com/rivo/tview"
)
func main() {
box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!")
if err := tview.NewApplication().SetRoot(box, true).Run(); err != nil {
panic(err)
}
}
看起来还是比较简单,大致学习了一下,更改了电影爬虫。
/*
功能:爬取电影网站播放地址
时间:2020.10.13
作者:Ease
说明:电影网站 https://www.ai66.cc
*/
package main
import (
"bytes"
"log"
"os"
"os/exec"
"strings"
"github.com/gocolly/colly"
"github.com/rivo/tview"
)
const url = "https://www.ai66.cc"
type link struct {
url string
title string
}
var (
app *tview.Application
list *tview.List
)
// 运行命令
func Shell(cmdStr string) string {
//fmt.Println(cmdStr)
cmd := exec.Command("/bin/bash", "-c", cmdStr)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Run()
return out.String()
}
//主功能
func main() {
if len(os.Args) > 2 {
log.Printf("格式:%s 网址", os.Args[0])
return
}
app = tview.NewApplication()
list = tview.NewList()
list.AddItem("搜索中...", "搜索中...", '0', nil)
go goHome()
if err := app.SetRoot(list, true).EnableMouse(true).Run(); err != nil {
panic(err)
}
}
// 首页
func goHome() {
var LinkList []link
if len(os.Args) == 1 {
LinkList = get(url)
} else {
LinkList = get(os.Args[1])
}
addList(LinkList)
}
// 更新列表
func addList(LinkList []link) {
list.Clear()
list.AddItem("退出 ---", "退出系统", '0', func() {
app.Stop()
})
list.AddItem("首页 ---", "进入首页", '1', func() {
go goHome()
})
for i, n := range LinkList {
no := rune(65 + i)
if i > 25 {
no = rune(97 + i)
}
list.AddItem(n.title, n.url, no, func() {
title, url := list.GetItemText(list.GetCurrentItem())
if title == "播放地址" {
Shell("firefox " + url)
} else {
go addList(get(url))
}
})
}
//更新界面
app.QueueUpdateDraw(func() {
app.SetRoot(list, true)
})
}
// 获取链接
func get(urlstr string) (ll []link) {
//创建 collector
c := colly.NewCollector()
c.AllowURLRevisit = false //不要重复
c.OnError(func(_ *colly.Response, err error) {
//log.Println("发生错误: ", err)
return
})
c.OnScraped(func(r *colly.Response) {
//log.Println("完成: ", r.Request.URL)
return
})
//step3
c.OnHTML("div>iframe", func(e *colly.HTMLElement) {
//log.Println("播放地址: ", e.Attr("src"))
ll = append(ll, link{url: e.Attr("src"), title: "播放地址"})
})
//step2
c.OnHTML("div.widget>a[href]", func(e *colly.HTMLElement) {
//log.Printf("发现链接: %s -> %s", strings.Trim(strings.Trim(e.Text, " "), "\n"), e.Attr("href"))
ll = append(ll, link{url: e.Attr("href"), title: strings.Trim(strings.Trim(e.Text, " "), "\n")})
})
//step1
c.OnHTML("div.thumbnail>a[href]", func(e *colly.HTMLElement) {
//log.Printf("发现链接: %s -> %s", strings.Trim(strings.Trim(e.Attr("title"), " "), "\n"), e.Attr("href"))
ll = append(ll, link{url: e.Attr("href"), title: strings.Trim(strings.Trim(e.Attr("title"), " "), "\n")})
})
c.OnHTML("div.pagination>a[href]", func(e *colly.HTMLElement) {
//log.Printf("发现链接: %s -> %s", strings.Trim(strings.Trim(e.Text, " "), "\n"), e.Attr("href"))
ll = append(ll, link{url: e.Attr("href"), title: strings.Trim(strings.Trim(e.Text, " "), "\n")})
})
//启动网页访问
c.Visit(urlstr)
return
}