Last active
March 14, 2020 17:37
-
-
Save melekhine/a73ffa0f51a489010443471b7ccfc682 to your computer and use it in GitHub Desktop.
Count words on webpages. Usage: echo http://golang.org | go run search.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"fmt" | |
"io" | |
"net/http" | |
"net/url" | |
"os" | |
"strings" | |
"sync" | |
) | |
// getLinks takes arguments from command line | |
func getLinks(out chan<- string) { | |
scanner := bufio.NewScanner(os.Stdin) | |
for scanner.Scan() { | |
link, err := url.ParseRequestURI(strings.TrimSpace(scanner.Text())) // not better way, but... | |
if err != nil { | |
fmt.Printf("Bad url trown away: %v\n", err) | |
continue // skip bad urls | |
} | |
out <- link.String() | |
} | |
close(out) | |
} | |
// countWords counts world on the page | |
// search word is CASE SENSITIVE | |
func countWords(out chan<- int, in <-chan string) { | |
var tokens = make(chan struct{}, 5) // max concurrent requests | |
var wg sync.WaitGroup | |
for link := range in { | |
tokens <- struct{}{} | |
wg.Add(1) | |
go countWordsRequest(out, tokens, &wg, link) | |
} | |
wg.Wait() | |
close(out) | |
} | |
// countWordsRequest make get requests, count words and release semaphore | |
func countWordsRequest(out chan<- int, tokens <-chan struct{}, wg *sync.WaitGroup, link string) { | |
defer wg.Done() | |
var count int | |
var body bytes.Buffer | |
res, err := http.Get(link) | |
<-tokens | |
if err != nil { | |
fmt.Printf("Http error: %v\n", err) | |
return | |
} | |
defer res.Body.Close() | |
io.Copy(&body, res.Body) | |
count = strings.Count(body.String(), "Go") | |
fmt.Printf("Count for %s: %d\n", link, count) | |
out <- count | |
} | |
// showResults show results and prints total | |
func showResults(in <-chan int) { | |
var total int | |
for c := range in { | |
total += c | |
} | |
fmt.Printf("Total: %d\n", total) | |
} | |
func main() { | |
var ( | |
links = make(chan string, 10) // limit reading from stdin too... | |
count = make(chan int) | |
) | |
go getLinks(links) | |
go countWords(count, links) | |
showResults(count) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment