簡介(Introduction)
-
如何安裝艾帐?
如何安裝
- Colly 只依賴于Go 語言溉瓶,你可以通過 安裝指南 安裝它
- 安裝Colly执俩,在終端輸入如下命令然后回車安裝Colly
go get -u github.com/gocolly/colly/...
-
入門
入門
- 開始使用Colly之前確保你已經(jīng)安裝最新版本晓勇,更詳細(xì)內(nèi)容見安裝指南
- 讓我們從一些簡單的例子開始
- 首先你需要導(dǎo)入Colly到你的代碼中
import "github.com/gocolly/colly"
收集器
Colly 的主要實例是收集器對象呜魄,當(dāng)Colly 收集器任務(wù)運行時师倔,收集器負(fù)責(zé)網(wǎng)絡(luò)通訊和執(zhí)行附加的回調(diào)任務(wù)构韵。你必須初始化收集器
c := colly.NewCollector()
回調(diào)
你可以把不同類型的回調(diào)函數(shù)附加到收集器上來控制收集任務(wù),然后取回信息趋艘,你可以在包文檔中查看相關(guān)章節(jié)
添加回調(diào)到收集器中
c.OnRequest(func(r *colly.Request) {
fmt.Println("Visiting", r.URL)
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
c.OnResponse(func(r *colly.Response) {
fmt.Println("Visited", r.Request.URL)
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
e.Request.Visit(e.Attr("href"))
})
c.OnHTML("tr td:nth-of-type(1)", func(e *colly.HTMLElement) {
fmt.Println("First column of a table row:", e.Text)
})
c.OnXML("http://h1", func(e *colly.XMLElement) {
fmt.Println(e.Text)
})
c.OnScraped(func(r *colly.Response) {
fmt.Println("Finished", r.Request.URL)
})
回調(diào)函數(shù)執(zhí)行順序
- OnRequest
在請求之前調(diào)用 - OnError
在請求中出現(xiàn)錯誤時調(diào)用 - OnResponse
響應(yīng)接收到之后調(diào)用 - OnHTML
OnResponse 正確執(zhí)行后疲恢,如果接收到的文本是HTML時執(zhí)行 - OnXML
OnResponse 正確執(zhí)行后,如果接收到的文本是XML時執(zhí)行 - OnScraped
OnXML 回調(diào)后調(diào)用
-
配置
配置
Colly 是一個高度自定義的爬蟲框架瓷胧,它提供合理的默認(rèn)配置显拳,而且提供了大量的配置去改變它
收集器配置
全面的收集器屬性列表可以在這兒查看,推薦使用colly.NewCollector(options...)這種方法來初始化收集器
使用默認(rèn)配置創(chuàng)建一個收集器
c1 := colly.NewCollector()
創(chuàng)建另外一個收集器搓萧,改變User-Agent 和 Url Revisit
c2 := colly.NewCollector(
colly.UserAgent("xy"),
colly.AllowURLRevisit(),
)
或者
c2 := colly.NewCollector()
c2.UserAgent = "xy"
c2.AllowURLRevisit = true
通過重新設(shè)置收集器的屬性可以在收集任務(wù)運行任何節(jié)點改變配置杂数。
一個很好的例子是 User-Agent 切換器遇八,在每個請求上改變User-Agent
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandomString() string {
b := make([]byte, rand.Intn(10)+10)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
c := colly.NewCollector()
c.OnRequest(func(r *colly.Request) {
r.Headers.Set("User-Agent", RandomString())
})
通過環(huán)境變量配置
收集器的默認(rèn)配置可以通過環(huán)境變量來改變,它允許我們在不通過編譯的情況下對配置進(jìn)行微調(diào)
環(huán)境變量解析是在收集器初始化的最后一步執(zhí)行耍休,所以每個變量在初始化后的改變都可能被環(huán)境變量配置覆蓋刃永。
環(huán)境變量配置
- ALLOWED_DOMAINS (多個域名用逗號分割)
- CACHE_DIR (string)
- DETECT_CHARSET (y/n)
- DISABLE_COOKIES (y/n)
- DISALLOWED_DOMAINS (多個域名用逗號分割)
- IGNORE_ROBOTSTXT (y/n)
- MAX_BODY_SIZE (int)
- MAX_DEPTH (int - 0 沒有限制)
- PARSE_HTTP_ERROR_RESPONSE (y/n)
- USER_AGENT (string)
HTTP 配置
Colly 使用golang的 http client 作為網(wǎng)絡(luò)層微王,HTTP設(shè)置可以通過改變默認(rèn)的HTTP roundtripper來調(diào)整
c := colly.NewCollector()
c.WithTransport(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
最佳實踐(Best Practices)
-
調(diào)試
調(diào)試
有時候?qū)?code>log.Println()函數(shù)放到回調(diào)函數(shù)中就足夠了施蜜,但有時候卻不行。Colly有收集器調(diào)試的內(nèi)置功能江兢,調(diào)試器接口可以使用不同的調(diào)試器實現(xiàn)喧锦。
將調(diào)試器添加到收集器
從Colly的repo中添加基本的日志調(diào)試器debug
import (
"github.com/gocolly/colly"
"github.com/gocolly/colly/debug"
)
func main() {
c := colly.NewCollector(colly.Debugger(&debug.LogDebugger{}))
// [..]
}
實現(xiàn)一個自定義的調(diào)試器
你通過實現(xiàn)debug.Debugger類可以創(chuàng)建任何種類的調(diào)試器读规。一個好的例子是 LogDebugger
-
分布式抓取
分布式爬蟲可以被不同方式實現(xiàn),取決于你的抓取任務(wù)是什么燃少。大多數(shù)情況下束亏,它足以擴(kuò)展網(wǎng)絡(luò)通信層,這可以使用代理和Colly的代理切換器輕松實現(xiàn)阵具。
代理選擇器
使用代理切換器仍然保持集中碍遍,而HTTP請求分布在多個代理之間。
Colly通過其SetProxyFunc()
函數(shù)來切換代理阳液。任意自定義的函數(shù)可以通過SetProxyFunc()
傳參怕敬,只要這個函數(shù)簽名為func(*http.Request) (*url.URL, error)
注意
通過使用 -D 可以將ssh 服務(wù)用到 sockets5代理上
Colly 有一個內(nèi)置的代理切換器,可以在每個請求上輪流切換代理列表
用法
package main
import (
"github.com/gocolly/colly"
"github.com/gocolly/colly/proxy"
)
func main() {
c := colly.NewCollector()
if p, err := proxy.RoundRobinProxySwitcher(
"socks5://127.0.0.1:1337",
"socks5://127.0.0.1:1338",
"http://127.0.0.1:8080",
); err == nil {
c.SetProxyFunc(p)
}
// ...
}
實現(xiàn)自定義的代理切換器:
var proxies []*url.URL = []*url.URL{
&url.URL{Host: "127.0.0.1:8080"},
&url.URL{Host: "127.0.0.1:8081"},
}
func randomProxySwitcher(_ *http.Request) (*url.URL, error) {
return proxies[random.Intn(len(proxies))], nil
}
// ...
c.SetProxyFunc(randomProxySwitcher)
分布式爬蟲
管理獨立的和分布式的爬蟲最好的辦法是你可以將爬蟲包裝在服務(wù)器中帘皿。服務(wù)器可以是各種服務(wù)的比如HTTP东跪,TCP服務(wù)器和Google APP Engine。使用自定義的存儲實現(xiàn)集中和持久化的cookie來處理訪問的url
注意
Colly內(nèi)置支持Google APP Engine鹰溜。如果你需要從標(biāo)準(zhǔn)的APP Engine中使用Colly虽填,別忘了調(diào)用Collector.Appengine(*http.Request)
。
一個實現(xiàn)的例子可以從這兒查看
分布式存儲
默認(rèn)情況下曹动,訪問的url和cookie數(shù)據(jù)存儲在內(nèi)存中斋日,這對短生命周期抓取任務(wù)很簡單。但它對處理大規(guī)模和長時間爬取任務(wù)有很多限制仁期。
通過實現(xiàn)colly/storage.Storage
接口桑驱,Colly可以使用很多后端存儲來代替默認(rèn)的內(nèi)存存儲。查看existing storages.
-
后端存儲
后端存儲
Colly可以通過內(nèi)存存儲cookie和訪問的url跛蛋,但它可以被任何實現(xiàn)了colly/storage.Storage的后端存儲覆蓋
現(xiàn)有的后端存儲
In-Memory Backend
Colly 默認(rèn)的后端存儲熬的,可以使用collector.SetStorage() 來覆蓋
Redis backend
詳細(xì)信息查閱redis example
SQLite3 backend
-
使用多個收集器
使用多個收集器
如果一個爬蟲任務(wù)足夠復(fù)雜或者有各種各樣的子任務(wù),推薦使用多個收集器赊级。一個很好地例子coursera course scraper
使用了2個收集器押框,一個處理視圖頁面列表,另外一個處理課程詳情理逊。
注意
在調(diào)試中使用collector.ID
來區(qū)分不同的收集器
克隆收集器
如果收集器中有非常相似的配置橡伞,你可以使用Clone()
方法來克隆收集器盒揉。Clone()
克隆收集器配置的副本,但不會添加回調(diào)函數(shù)兑徘。
c := colly.NewCollector(
colly.UserAgent("myUserAgent"),
colly.AllowedDomains("foo.com", "bar.com"),
)
// Custom User-Agent and allowed domains are cloned to c2
c2 := c.Clone()
在收集器之間傳遞自定義參數(shù)
使用收集器的Request()
方法可以在其他收集器中共享上下文
一個共享上下文的例子:
c.OnResponse(func(r *colly.Response) {
r.Ctx.Put(r.Headers.Get("Custom-Header"))
c2.Request("GET", "https://foo.com/", nil, r.Ctx, nil)
}
-
爬蟲配置
爬蟲配置
Colly的默認(rèn)配置已經(jīng)經(jīng)過優(yōu)化刚盈,可以在一個任務(wù)重抓取數(shù)量較小的站點。如果你想抓取上百萬個站點挂脑,這樣的啟動不是最好的藕漱。這里有一些調(diào)整:
使用持久化的后端存儲
默認(rèn)情況下,Colly將cookie和訪問過的URL存儲在內(nèi)存中崭闲,你可以使用任意自定義的后端存儲來替換內(nèi)置的內(nèi)存存儲肋联。在這里查看更多詳情。
對于遞歸調(diào)用的長任務(wù)使用異步存儲
默認(rèn)情況下刁俭,Colly在請求未完成時會阻塞橄仍。所以,在回調(diào)函數(shù)中遞歸調(diào)用Collector.Visit
會產(chǎn)生不斷增長的堆棧牍戚,使用Collector.Async = true
可以避免(不要忘記了與異步一起使用c.Wait()
)
禁用或限制連接保持活動狀態(tài)
Colly使用HTTP keep-alive提高爬取速度侮繁,它需要打開文件描述符,所以max-fd
限制可以輕松達(dá)到長時間運行任務(wù)
使用如下代碼可以禁用HTTP keep-alive
c := colly.NewCollector()
c.WithTransport(&http.Transport{
DisableKeepAlives: true,
})
-
擴(kuò)展
擴(kuò)展
擴(kuò)展是Colly附帶的小型輔助工具翘魄,插件列表可以在此處獲得
用法
以下示例啟用隨機(jī)User-Agent切換器和Referrer setter擴(kuò)展鼎天,并訪問httpbin.org兩次
import (
"log"
"github.com/gocolly/colly"
"github.com/gocolly/colly/extensions"
)
func main() {
c := colly.NewCollector()
visited := false
extensions.RandomUserAgent(c)
extensions.Referrer(c)
c.OnResponse(func(r *colly.Response) {
log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.Visit("http://httpbin.org/get")
}