写爬虫的时候总会遇到爬取速度过快而被封IP的情况,这个时候就需要使用代理了。在https://github.com/henson/ProxyPool
的启发下,决定自己实现一个代理池。项目已经开源在github。
https://github.com/AceDarkkinght/GoProxyCollector
开发环境windows 7,Go 1.8.4
数据来源
https://www.kuaidaili.com
https://proxy.coderbusy.com
collector 收集器,抓取各个网站的代理
result 表示抓取的结果
scheduler 负责任务调度,包括启动collector和入库
server 启动一个web服务,提供取结果的API
storage 存储结果,通过接口可以使用别的数据库
util 一些常用的工具方法
verifier ip的验证与入库出库
实现
collector
collector 支持两种模式,分别是使用goquery对网页元素进行选择和使用正则表达式匹配我们需要的信息。直接上代码吧。
```go
// github.com\AceDarkkinght\GoProxyCollector\collector\selectorCollector.go
func (c SelectorCollector) Collect(ch chan<- result.Result) {
// 退出前关闭channel。
defer close(ch)
response, _, errs := gorequest.New().Get(c.currentUrl).Set("User-Agent", util.RandomUA()).End()
/* 省略部分代码 */
// 有些网站不是UTF-8编码的,需要进行转码。
var decoder mahonia.Decoder
if c.configuration.Charset != "utf-8" {
decoder = mahonia.NewDecoder(c.configuration.Charset)
}
// 使用goquery。
doc, err := goquery.NewDocumentFromReader(response.Body)
if err != nil {
seelog.Errorf("parse %s error:%v", c.currentUrl, err)
return
}
// 大部分代理网站的代理列表都放在一个table里,先选出table再循环里面的元素。
selection := doc.Find(c.selectorMap["table"][0])
selection.Each(func(i int, sel *goquery.Selection) {
var (
ip string
port int
speed float64
location string
)
})
}
// github.com\AceDarkkinght\GoProxyCollector\collector\regexCollector.go
func (c RegexCollector) Collect(ch chan<- result.Result) {
response, bodyString, errs := gorequest.New().Get(c.currentUrl).Set("User-Agent", util.RandomUA()).End()
}
- ##### result result很简单,只是用来表示collector爬取的结果。go
// github.com\AceDarkkinght\GoProxyCollector\result\result.go
type Result struct {
Ip string json:"ip"
Port int json:"port"
Location string json:"location,omitempty"
Source string json:"source"
Speed float64 json:"speed,omitempty"
}
- ##### scheduler scheduler负责完成一些初始化的工作以及调度collector任务。不同的任务在不同的goroutine中运行,goroutine之间通过channel进行通信。go
// github.com\AceDarkkinght\GoProxyCollector\scheduler\scheduler.go
func Run(configs collector.Configs, storage storage.Storage) {
/ 省略部分代码 */