day7函数 练习
parent
d33b37a04a
commit
5ab496ae36
|
@ -0,0 +1,92 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"Study/src/study/day7Function/HtmlTools"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 函数字面量允许我们在使用函数时,再定义它。
|
||||
// 通过这种技巧,我们可以改写之前对strings.Map的调用:
|
||||
str1 := strings.Map(func(r rune) rune { return r + 1 }, "HAL-9000")
|
||||
fmt.Println(str1)
|
||||
|
||||
// 定义变量保存square的返回值
|
||||
sqar := square()
|
||||
// 此时sqar里保存的是返回值,也就是相当于一个函数类型的变量
|
||||
// sqar 相当于
|
||||
|
||||
//sqar = func(x int) int {
|
||||
// x++
|
||||
// return x * x
|
||||
//}
|
||||
|
||||
// 只不过在sqar := square()里,x的值不来自于形参的x,而是来自于上一级快语句square中。
|
||||
|
||||
sqar = square()
|
||||
fmt.Println(sqar()) // 1
|
||||
fmt.Println(sqar()) // 4
|
||||
fmt.Println(sqar()) // 9
|
||||
fmt.Println(sqar()) // 16
|
||||
// 我们看到变量的生命周期不由它的作用域决定:squares返回后,变量x仍然隐式的存在于sqar中。
|
||||
// 直到我们销毁sqar变量,资源被gc回收,或者程序运行完成被系统回收
|
||||
// 这就是 闭包(closures)
|
||||
// 闭包 一定是在返回的函数里面使用了外部函数的资源
|
||||
// 闭包 通常用于扩展函数的功能
|
||||
links, err := Extract()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
for _, link := range links {
|
||||
fmt.Println(link)
|
||||
}
|
||||
}
|
||||
|
||||
// 函数square返回另一个类型为 func() int 的函数,
|
||||
// 对square的第一次调用会生成第一个局部变量x并返回一个匿名函数,
|
||||
// 每次调用此匿名函数时, 改函数都会使x的值+1, 再返回x的平方,
|
||||
// 第二次调用square时, 会生成新的匿名函数。
|
||||
// 新的匿名函数操作的也是一个新的x变量
|
||||
// ⚠️需要注意x的作用域和生存周期
|
||||
// ⚠️x的作用域在匿名函数里是属于上一级块语句提供的,
|
||||
// ⚠️所以只要square的返回值被保存了
|
||||
// ⚠️匿名函数就可以访问到x变量
|
||||
func square() func() int {
|
||||
var x int
|
||||
return func() int {
|
||||
x++
|
||||
return x * x
|
||||
}
|
||||
}
|
||||
|
||||
// Extract
|
||||
//
|
||||
// 现在links中存储的不是href属性的原始值,
|
||||
// 而是通过resp.Request.URL解析后的值。
|
||||
// 解析后,这些连接以绝对路径的形式存在,可以直接被http.Get访问。
|
||||
func Extract() ([]string, error) {
|
||||
node, resp := HtmlTools.GetHtmlS()
|
||||
var links []string
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key != "href" {
|
||||
continue
|
||||
}
|
||||
// 将相对路径和url的内容组合在一起形成完整的绝对路径
|
||||
link, err := resp.Request.URL.Parse(a.Val)
|
||||
if err != nil {
|
||||
// 忽略掉报error的URL
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
// 将link添加到切片
|
||||
links = append(links, link.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
HtmlTools.ForEachNode(node, visitNode, nil)
|
||||
return links, nil
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"Study/src/study/day7Function/HtmlTools"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// 接下来,我们讨论一个有点学术性的例子,考虑这样一个问题:
|
||||
// 给定一些计算机课程,每个课程都有前置课程,只有完成了前置课程才可以开始当前课程的学习;
|
||||
// 我们的目标是选择出一组课程,这组课程必须确保按顺序学习时,能全部被完成。每个课程的前置课程如下:
|
||||
|
||||
// prereqs记录了每个课程的前置课程
|
||||
var prereqs = map[string][]string{
|
||||
"algorithms": {"data structures"},
|
||||
"linear algebra": {"calculus"},
|
||||
"calculus": {"linear algebra"},
|
||||
"compilers": {
|
||||
"data structures",
|
||||
"formal languages",
|
||||
"computer organization",
|
||||
},
|
||||
"data structures": {"discrete math"},
|
||||
"databases": {"data structures"},
|
||||
"discrete math": {"intro to programming"},
|
||||
"formal languages": {"discrete math"},
|
||||
"networks": {"operating systems"},
|
||||
"operating systems": {"data structures", "computer organization"},
|
||||
"programming languages": {"data structures", "computer organization"},
|
||||
}
|
||||
|
||||
func main() {
|
||||
// for i, course := range topoSort(prereqs) {
|
||||
// fmt.Printf("%d:\t%s\n", i, course)
|
||||
// }
|
||||
//fmt.Println(hasCycle(prereqs))
|
||||
//topoSort(prereqs)
|
||||
//fmt.Printf("%v", len(prereqs["qqq"]))
|
||||
//BreadthFirst(crawl, []string{"all"})
|
||||
}
|
||||
|
||||
// BreadthFirst
|
||||
// calls f() for each item in the worklist.
|
||||
// Any items returned by f() are added to the worklist.
|
||||
// f() is called at most once for each item.
|
||||
//
|
||||
// -
|
||||
//
|
||||
// BreadthFirst 队列中的每节点都调用f()。
|
||||
// f()返回的所有节点都被添加到队列中。
|
||||
// 对每个节点最多调用一次f()。
|
||||
//
|
||||
// f func(item string) []string
|
||||
// returns []string
|
||||
func BreadthFirst(f func(item string) []string, worklist []string) {
|
||||
// seen
|
||||
seen := make(map[string]bool)
|
||||
for len(worklist) > 0 {
|
||||
// 复制当前队列
|
||||
items := worklist
|
||||
// 清空队列
|
||||
worklist = nil
|
||||
// 遍历复制的当前队列
|
||||
for _, item := range items {
|
||||
// 判断seen, 防止重复添加到队列
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
// 添加到队列
|
||||
worklist = append(worklist, f(item)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// crawl 此函数返回一个[]string, 内容为url
|
||||
func crawl(url string) []string {
|
||||
fmt.Println(url)
|
||||
list, err := HtmlTools.Extract()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
return list
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package HtmlTools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"log"
|
||||
"net/http"
|
||||
|
@ -26,3 +27,85 @@ func GetHtml() *html.Node {
|
|||
return doc
|
||||
|
||||
}
|
||||
func GetHtmlResponse(url string) (*html.Node, *http.Response) {
|
||||
// 检查参数
|
||||
if url == "" {
|
||||
url = "https://go.dev/"
|
||||
}
|
||||
resp, err := http.Get("https://go.dev/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err := resp.Body.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
doc, err := html.Parse(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, nil
|
||||
}
|
||||
return doc, resp
|
||||
|
||||
}
|
||||
|
||||
// ForEachNode 深度遍历 n, pre和post分别表示压栈和出栈时执行的动作
|
||||
//
|
||||
// n *html.Node
|
||||
// pre func(n *html.Node)
|
||||
// post func(n *html.Node)
|
||||
//
|
||||
// 将 ForEachNode() 移动到单独的软件包,供以后方便调用
|
||||
func ForEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
//for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
// forEachNode(c, pre, post)
|
||||
//}
|
||||
ForEachNode(n.FirstChild, pre, post)
|
||||
ForEachNode(n.NextSibling, pre, post)
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract
|
||||
//
|
||||
// 现在links中存储的不是href属性的原始值,
|
||||
// 而是通过resp.Request.URL解析后的值。
|
||||
// 解析后,这些连接以绝对路径的形式存在,可以直接被http.Get访问。
|
||||
//
|
||||
// return []string, error
|
||||
//
|
||||
// 将Extract()移动到单独的软件包,供以后方便调用
|
||||
func Extract() ([]string, error) {
|
||||
node, resp := GetHtmlResponse("")
|
||||
var links []string
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key != "href" {
|
||||
continue
|
||||
}
|
||||
// 将相对路径和url的内容组合在一起形成完整的绝对路径
|
||||
link, err := resp.Request.URL.Parse(a.Val)
|
||||
if err != nil {
|
||||
// 忽略掉报error的URL
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
// 将link添加到切片
|
||||
links = append(links, link.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
ForEachNode(node, visitNode, nil)
|
||||
return links, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// topoSort 函数返回一个切片,其中的字符串代表了可以安全学习的课程。
|
||||
// m 参数表示每个课程的前置课程的映射。
|
||||
//
|
||||
// func topoSort(m map[string][]string) []string {
|
||||
// // 定义一个 order 切片,用于存储排序后的课程名。
|
||||
// var order []string
|
||||
// // 定义一个 seen 映射,用于记录每个课程是否已经遍历过。
|
||||
// seen := make(map[string]bool)
|
||||
// // 定义一个 visitAll 函数,用于遍历所有的课程。
|
||||
// var visitAll func(items map[string]bool)
|
||||
// // 定义 visitAll 函数的实现体。
|
||||
// visitAll = func(items map[string]bool) {
|
||||
// // 遍历 items 参数中的所有课程。
|
||||
// for item := range items {
|
||||
// // 如果当前课程没有遍历过。
|
||||
// if !seen[item] {
|
||||
// // 将当前课程标记为已遍历。
|
||||
// seen[item] = true
|
||||
// // 递归调用 visitAll 函数,继续遍历当前课程的前置课程。
|
||||
// visitAll(m[item])
|
||||
// // 将当前课程追加到 order 切片的末尾。
|
||||
// order = append(order, item)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // 定义一个 keys 切片,用于存储 m 参数中所有课程的名称。
|
||||
// var keys = make(map[string]bool)
|
||||
// // 遍历 m 参数中的所有课程。
|
||||
// for key := range m {
|
||||
// // 将当前课程的名称追加到 keys 切片的末尾。
|
||||
// keys[key] = true
|
||||
// }
|
||||
// visitAll(keys)
|
||||
// // 返回 order 切片。
|
||||
// return order
|
||||
//
|
||||
// }
|
||||
|
||||
// topoSort 函数用于对给定的项目进行拓扑排序。
|
||||
// 它接收一个字符串到字符串切片的映射 m,其中 m[i] 存储了项目 i 的依赖项目。
|
||||
// 函数返回一个切片,表示拓扑排序后项目的顺序。
|
||||
func topoSort(m map[string][]string) []string {
|
||||
// order 存储了项目的拓扑排序顺序。
|
||||
var order []string
|
||||
// seen 记录了已访问过的项目。
|
||||
seen := make(map[string]bool)
|
||||
// visitAll 函数递归访问 items 切片中的每个项目,并将它们按照正确的拓扑顺序添加到 order 切片中。
|
||||
var visitAll func(items []string)
|
||||
visitAll = func(items []string) {
|
||||
for _, item := range items {
|
||||
// 如果当前项目还没有被访问过,则递归调用 visitAll 函数,并将当前项目加入到 order 切片中。
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
visitAll(m[item])
|
||||
order = append(order, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
// keys 存储了 m 中所有键的切片。
|
||||
var keys []string
|
||||
// 遍历 m 中的每个键,并将它们存储到 keys 切片中。
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
// 调用 visitAll 函数,并传入 keys 切片,从而从依赖图中的“叶子”节点(即没有依赖的项目)开始,
|
||||
// 逐步往上遍历依赖关系,并将项目添加到 order 切片中。
|
||||
visitAll(keys)
|
||||
// 返回 order 切片,表示拓扑排序后项目的顺序。
|
||||
return order
|
||||
}
|
||||
|
||||
func main() {
|
||||
// prereqs 记录了每个课程的前置课程
|
||||
var prereqs = map[string][]string{
|
||||
"algorithms": {"data structures"},
|
||||
"calculus": {"linear algebra"},
|
||||
"compilers": {
|
||||
"data structures",
|
||||
"formal languages",
|
||||
"computer organization",
|
||||
},
|
||||
"data structures": {"discrete math"},
|
||||
"databases": {"data structures"},
|
||||
"discrete math": {"intro to programming"},
|
||||
"formal languages": {"discrete math"},
|
||||
"networks": {"operating systems"},
|
||||
"operating systems": {"data structures", "computer organization"},
|
||||
"programming languages": {"data structures", "computer organization"},
|
||||
}
|
||||
// 调用 topoSort 函数,并将返回值存储到 courses 切片中。
|
||||
courses := topoSort(prereqs)
|
||||
// 遍历 courses 切片中的每个项目,并以“索引:项目”的格式将它们输出到屏幕上。
|
||||
// 这么做的目的是使map的输出是有序的
|
||||
for i := 0; i < len(courses); i++ {
|
||||
fmt.Printf("%d:\t%s\n", i+1, courses[i])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// prereqs记录了每个课程的前置课程
|
||||
var prereqs = map[string][]string{
|
||||
"algorithms": {"data structures"},
|
||||
// ---环---
|
||||
"linear algebra": {"calculus"},
|
||||
"calculus": {"linear algebra"},
|
||||
// ---环---
|
||||
"compilers": {
|
||||
"data structures",
|
||||
"formal languages",
|
||||
"computer organization",
|
||||
},
|
||||
"data structures": {"discrete math"},
|
||||
"databases": {"data structures"},
|
||||
"discrete math": {"intro to programming"},
|
||||
"formal languages": {"discrete math"},
|
||||
"networks": {"operating systems"},
|
||||
"operating systems": {"data structures", "computer organization"},
|
||||
"programming languages": {"data structures", "computer organization"},
|
||||
}
|
||||
|
||||
// hasCycle 检查图中是否存在环
|
||||
func hasCycle(m map[string][]string) bool {
|
||||
// visited 记录已经访问过的节点
|
||||
visited := make(map[string]bool)
|
||||
// dfs 函数用来进行深度优先搜索
|
||||
var dfs func(string, map[string]bool) bool
|
||||
dfs = func(item string, path map[string]bool) bool {
|
||||
// 如果当前节点已经被访问过,则返回 false
|
||||
if visited[item] {
|
||||
return false
|
||||
}
|
||||
// 将当前节点标记为已访问,并加入访问路径
|
||||
visited[item] = true
|
||||
path[item] = true
|
||||
// 遍历当前节点的所有相邻节点
|
||||
for _, next := range m[item] {
|
||||
|
||||
// 如果相邻节点已经在访问路径上,说明存在环,返回 true
|
||||
if path[next] || dfs(next, path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 将当前节点从访问路径中移除,并返回 false
|
||||
delete(path, item)
|
||||
return false
|
||||
}
|
||||
// 遍历 map 中的每个节点,并调用 dfs 函数检查是否存在环
|
||||
for k := range m {
|
||||
path := make(map[string]bool)
|
||||
if dfs(k, path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 如果所有节点都检查完,则说明图中不存在环,返回 false
|
||||
return false
|
||||
}
|
||||
func main() {
|
||||
// 有环则输出true
|
||||
fmt.Println(hasCycle(prereqs))
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"Study/src/study/day7Function/HtmlTools"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// forEachNode 针对每个结点x,都会调用pre(x)和post(x)。
|
||||
// pre和post都是可选的。
|
||||
// 遍历孩子结点之前,pre被调用
|
||||
// 遍历孩子结点之后,post被调用
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var depth int
|
||||
|
||||
var startElement func(n *html.Node) = func(n *html.Node) {
|
||||
if n.Type == html.ElementNode {
|
||||
fmt.Printf("%*s<%s>\n", depth*2, "", n.Data)
|
||||
depth++
|
||||
}
|
||||
}
|
||||
endElement := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode {
|
||||
depth--
|
||||
fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)
|
||||
}
|
||||
}
|
||||
forEachNode(HtmlTools.GetHtml(), startElement, endElement)
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"Study/src/study/day7Function/HtmlTools"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BreadthFirst 队列中的每节点都调用f()。
|
||||
// f()返回的所有节点都被添加到队列中。
|
||||
// 对每个节点最多调用一次f()。
|
||||
func BreadthFirst(f func(item string) []string, worklist []string) {
|
||||
// seen
|
||||
seen := make(map[string]bool)
|
||||
for len(worklist) > 0 {
|
||||
// 复制当前队列
|
||||
items := worklist
|
||||
// 清空队列
|
||||
worklist = nil
|
||||
// 遍历复制的当前队列
|
||||
for _, item := range items {
|
||||
// 判断seen, 防止重复添加到队列
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
// 添加到队列
|
||||
worklist = append(worklist, f(item)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExtractRestructure 从HTML文档中提取链接,并将相对路径转换为绝对路径
|
||||
//
|
||||
// URL string, 要提取链接的HTML文档
|
||||
// isSave bool, 是否保存提取到的链接对应的页面
|
||||
// saveOriginOnly bool, 是否只保存与当前页面域名相同的页面
|
||||
//
|
||||
// return []string, error, 提取到的链接列表和错误信息
|
||||
func ExtractRestructure(URL string, isSave bool, saveOriginOnly bool) ([]string, error) {
|
||||
// 检查参数
|
||||
if URL == "" {
|
||||
URL = "https://go.dev/"
|
||||
}
|
||||
node, resp := HtmlTools.GetHtmlResponse(URL)
|
||||
originURL := resp.Request.URL.Host
|
||||
var links []string
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key != "href" {
|
||||
continue
|
||||
}
|
||||
// 将相对路径和url的内容组合在一起形成完整的绝对路径
|
||||
link, err := resp.Request.URL.Parse(a.Val)
|
||||
if err != nil {
|
||||
// 忽略掉报error的URL
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 将link添加到切片
|
||||
links = append(links, link.String())
|
||||
// 判断是否只保存同一域名下的地址
|
||||
if saveOriginOnly && (link.Host != originURL) {
|
||||
continue
|
||||
}
|
||||
// 判断是否保存页面
|
||||
if isSave && link.String() != "" {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
filePath := getCurrentAbPath() + "/www/urls.txt"
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("文件打开失败", err)
|
||||
}
|
||||
//及时关闭file句柄
|
||||
defer file.Close()
|
||||
//写入文件时,使用带缓存的 *Writer
|
||||
write := bufio.NewWriter(file)
|
||||
if _, err := write.WriteString(link.String() + "\r\n"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 将缓存写入文件
|
||||
if err := write.Flush(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HtmlTools.ForEachNode(node, visitNode, nil)
|
||||
return links, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// crawl 此函数返回一个[]string, 内容为url
|
||||
crawl := func(url string) []string {
|
||||
fmt.Println("Crawl:", url)
|
||||
list, err := ExtractRestructure(url, true, true)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Crawl the web breadth-first,
|
||||
// starting from the command-line arguments.
|
||||
BreadthFirst(crawl, []string{"https://go.dev/"})
|
||||
}
|
||||
|
||||
// see https://zhuanlan.zhihu.com/p/363714760
|
||||
// 最终方案-全兼容
|
||||
func getCurrentAbPath() string {
|
||||
dir := getCurrentAbPathByExecutable()
|
||||
if strings.Contains(dir, getTmpDir()) {
|
||||
return getCurrentAbPathByCaller()
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
// 获取系统临时目录,兼容go run
|
||||
func getTmpDir() string {
|
||||
dir := os.Getenv("TEMP")
|
||||
if dir == "" {
|
||||
dir = os.Getenv("TMP")
|
||||
}
|
||||
res, _ := filepath.EvalSymlinks(dir)
|
||||
return res
|
||||
}
|
||||
|
||||
// 获取当前执行文件绝对路径
|
||||
func getCurrentAbPathByExecutable() string {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
|
||||
return res
|
||||
}
|
||||
|
||||
// 获取当前执行文件绝对路径(go run)
|
||||
func getCurrentAbPathByCaller() string {
|
||||
var abPath string
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if ok {
|
||||
abPath = path.Dir(filename)
|
||||
}
|
||||
return abPath
|
||||
}
|
|
@ -36,7 +36,7 @@ func main() {
|
|||
// return nil
|
||||
//}
|
||||
////调用
|
||||
//forEachNode(HtmlTools.GetHtml(), ElementByID, "a")
|
||||
//forEachNode(HtmlTools.GetHtmlS(), ElementByID, "a")
|
||||
|
||||
var each func(doc *html.Node) func(id string) *html.Node
|
||||
each = func(doc *html.Node) func(id string) *html.Node {
|
||||
|
@ -67,7 +67,7 @@ func main() {
|
|||
return ResultNode
|
||||
}
|
||||
}
|
||||
//each1 := each(HtmlTools.GetHtml())
|
||||
//each1 := each(HtmlTools.GetHtmlS())
|
||||
//each1("a")
|
||||
|
||||
// 手动清除ResultNode的内容
|
Loading…
Reference in New Issue