-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
93 lines (81 loc) · 1.79 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main
import (
"fmt"
"net/http"
"runtime"
"time"
"golang.org/x/net/html"
)
var fetched map[string]bool
type result struct {
url string
urls []string
err error
depth int
}
// Crawl uses findLinks to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int) {
runtime.GOMAXPROCS(runtime.NumCPU())
results := make(chan *result)
fetch := func(url string, depth int) {
urls, err := findLinks(url)
results <- &result{url, urls, err, depth}
}
go fetch(url, depth)
fetched[url] = true
for fetching := 1; fetching > 0; fetching-- {
res := <-results
if res.err != nil {
// fmt.Println(res.err)
continue
}
fmt.Printf("found: %s\n", res.url)
if res.depth > 0 {
for _, u := range res.urls {
if !fetched[u] {
fetching++
go fetch(u, res.depth-1)
fetched[u] = true
}
}
}
}
close(results)
}
func main() {
fetched = make(map[string]bool)
now := time.Now()
Crawl("http://github.com/aditya43", 2)
fmt.Println("time taken:", time.Since(now))
}
func findLinks(url string) ([]string, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, fmt.Errorf("getting %s: %s", url, resp.Status)
}
doc, err := html.Parse(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("parsing %s as HTML: %v", url, err)
}
return visit(nil, doc), nil
}
// visit appends to links each link found in n, and returns the result.
func visit(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
return links
}