switch to using a limited number of crawler worker functions
This commit is contained in:
1 parent
e80ef1b1b9
commit
3f85a0e7c0
1 file changed
+38
-11
+38
-11
@@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// docrawl begins crawling the site at "homeurl"
|
// doCrawl begins crawling the site at "homeurl"
|
||||||
func doCrawl(homeurl string) itemSlice {
|
func doCrawl(homeurl string) itemSlice {
|
||||||
// set of what we have already crawled, our results
|
// set of what we have already crawled, our results
|
||||||
crawled := make(itemMap)
|
crawled := make(itemMap)
|
||||||
@@ -17,8 +17,14 @@ func doCrawl(homeurl string) itemSlice {
|
|||||||
// already crawled http://a.com/index.html, or vice versa
|
// already crawled http://a.com/index.html, or vice versa
|
||||||
crawledStripped := make(itemMap)
|
crawledStripped := make(itemMap)
|
||||||
|
|
||||||
// a channel to receive our results on
|
// channels to send work to and receive our results on
|
||||||
rchan := make(chan *httpItem)
|
rxchan := make(chan *httpItem)
|
||||||
|
txchan := make(chan *httpItem)
|
||||||
|
|
||||||
|
// spin up our crawler workers
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go crawlListner(txchan, rxchan)
|
||||||
|
}
|
||||||
|
|
||||||
// start a ticker which we'll use to output status and check for completion
|
// start a ticker which we'll use to output status and check for completion
|
||||||
ticker := time.Tick(250 * time.Millisecond)
|
ticker := time.Tick(250 * time.Millisecond)
|
||||||
@@ -35,12 +41,12 @@ func doCrawl(homeurl string) itemSlice {
|
|||||||
// start the home page crawl
|
// start the home page crawl
|
||||||
crawled[homeitem.url.String()] = homeitem
|
crawled[homeitem.url.String()] = homeitem
|
||||||
crawledStripped[stripURL(homeitem.url)] = homeitem
|
crawledStripped[stripURL(homeitem.url)] = homeitem
|
||||||
go crawlItem(homeitem, rchan)
|
txchan <- homeitem
|
||||||
|
|
||||||
// wait for results
|
// wait for results
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case r := <-rchan: // new results?
|
case r := <-rxchan: // new results?
|
||||||
// add result to our results map
|
// add result to our results map
|
||||||
crawled[r.url.String()] = r
|
crawled[r.url.String()] = r
|
||||||
|
|
||||||
@@ -77,7 +83,9 @@ func doCrawl(homeurl string) itemSlice {
|
|||||||
crawlingCount++
|
crawlingCount++
|
||||||
crawled[c.url.String()] = c
|
crawled[c.url.String()] = c
|
||||||
crawledStripped[stripURL(c.url)] = c
|
crawledStripped[stripURL(c.url)] = c
|
||||||
go crawlItem(c, rchan)
|
go func(newItem *httpItem) {
|
||||||
|
txchan <- newItem
|
||||||
|
}(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-ticker: // our regular ticker. for status output and checking for completion.
|
case <-ticker: // our regular ticker. for status output and checking for completion.
|
||||||
@@ -86,6 +94,10 @@ func doCrawl(homeurl string) itemSlice {
|
|||||||
|
|
||||||
// see if we're finished
|
// see if we're finished
|
||||||
if crawlingCount == 0 {
|
if crawlingCount == 0 {
|
||||||
|
// close our channels, signalling any workers to exit
|
||||||
|
close(txchan)
|
||||||
|
close(rxchan)
|
||||||
|
|
||||||
// finished! convert results map to a slice and return it
|
// finished! convert results map to a slice and return it
|
||||||
rslice := itemSlice{}
|
rslice := itemSlice{}
|
||||||
for _, v := range crawled {
|
for _, v := range crawled {
|
||||||
@@ -97,21 +109,36 @@ func doCrawl(homeurl string) itemSlice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// crawlListner is a for+select wrapper around crawlItem that listens
|
||||||
|
// for new jobs and sends them off to crawlItem
|
||||||
|
func crawlListner(txchan <-chan *httpItem, rxchan chan<- *httpItem) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case newJob, ok := <-txchan:
|
||||||
|
if !ok {
|
||||||
|
// channel closed, finish
|
||||||
|
return
|
||||||
|
}
|
||||||
|
crawlItem(newJob, rxchan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// crawlItem crawls a single httpItem, fetching the header, hte page, parsing it,
|
// crawlItem crawls a single httpItem, fetching the header, hte page, parsing it,
|
||||||
// and filling out its structure as much as possible
|
// and filling out its structure as much as possible
|
||||||
func crawlItem(item *httpItem, rchan chan<- *httpItem) {
|
func crawlItem(item *httpItem, rxchan chan<- *httpItem) {
|
||||||
// make sure this item is the same domain (i.e. URL "host part") as its referrer
|
// make sure this item is the same domain (i.e. URL "host part") as its referrer
|
||||||
if item.refurl != nil && item.url.Host != item.refurl.Host {
|
if item.refurl != nil && item.url.Host != item.refurl.Host {
|
||||||
// skip URLs associated with other Hosts
|
// skip URLs associated with other Hosts
|
||||||
item.linkType = tRemote
|
item.linkType = tRemote
|
||||||
rchan <- item
|
rxchan <- item
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch page
|
// fetch page
|
||||||
text, err := fetchPage(item)
|
text, err := fetchPage(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rchan <- item
|
rxchan <- item
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +146,7 @@ func crawlItem(item *httpItem, rchan chan<- *httpItem) {
|
|||||||
title, links := parseLinks(text) // TODO remove error from parseLinks, not needed
|
title, links := parseLinks(text) // TODO remove error from parseLinks, not needed
|
||||||
if err != nil {
|
if err != nil {
|
||||||
item.linkType = tBroken
|
item.linkType = tBroken
|
||||||
rchan <- item
|
rxchan <- item
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item.title = title
|
item.title = title
|
||||||
@@ -134,7 +161,7 @@ func crawlItem(item *httpItem, rchan chan<- *httpItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send back our item struct now that it's all filled out
|
// send back our item struct now that it's all filled out
|
||||||
rchan <- item
|
rxchan <- item
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
Reference in new issue
Block a user