(原) 回归:字符界面库 Tview

原创文章,请后转载,并注明出处。

字符界面与图形界面只能说各有优势。“老年人”比较喜迎字符界面:简单、轻巧,对电脑要求低,专注于内容。

考虑到爬电影通过命令行还是比较的反人类,想给它搭个简单的命令行界面。

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
}

相关文章