golang初学之goroutine---web爬虫

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

go tour 练习 https://tour.go-zh.org/concurrency/10

package main

import (
	"fmt"
	"sync"
	"time"
)

type Fetcher interface {
	// Fetch 返回 URL 的 body 内容,并且将在这个页面上找到的 URL 放到一个 slice 中。
	Fetch(url string) (body string, urls []string, err error)
}

// SafeCounter 的并发使用是安全的。
type SafeUrlMap struct {
	v   map[string]bool
	mux sync.Mutex
}

func (c *SafeUrlMap) Put(key string) {
	c.mux.Lock()
	c.v[key] = true
	c.mux.Unlock()
}

func (c *SafeUrlMap) Contains(key string) bool {
	c.mux.Lock()
	defer c.mux.Unlock()
	_, ok := c.v[key]
	return ok
}

type Resp struct {
	url string
	body string
}

var urlMap *SafeUrlMap = &SafeUrlMap{v: make(map[string]bool)}
// Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面,直到达到最大深度。
func Crawl(url string, depth int, fetcher Fetcher, ch chan Resp) {
	if depth <= 0 {
		return
	}
	urlMap.Put(url)
	body, urls, err := fetcher.Fetch(url)
	if err != nil {
		fmt.Println(err)
		return
	}
	ch <- Resp{url:url, body:body}

	for _, u := range urls {
		if urlMap.Contains(u) {
			fmt.Printf("Have Processed: %s\n", u)
			continue
		}
		go Crawl(u, depth-1, fetcher, ch)
	}
	
	return
}

func main() {
	ch := make(chan Resp)
	go Crawl("http://golang.org/", 4, fetcher, ch)
	boom := time.After(3 * time.Second)
	for {
		select {
			case r := <-ch:
				fmt.Printf("found: %s %q\n", r.url, r.body)
				boom = time.After(3 * time.Second)
			case <-boom:
				fmt.Printf("time out\n")
				return
			}
	}
		
}

// fakeFetcher 是返回若干结果的 Fetcher。
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := f[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher 是填充后的 fakeFetcher。
var fetcher = fakeFetcher{
	"http://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"http://golang.org/",
			"http://golang.org/cmd/",
			"http://golang.org/pkg/fmt/",
			"http://golang.org/pkg/os/",
		},
	},
	"http://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
	"http://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
}

  


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

本文来自:博客园

感谢作者:enfreeworld

查看原文:golang初学之goroutine---web爬虫

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

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