這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
首發文來源:CSDN Golang原生爬蟲 簡單爬蟲實現 不依賴第三方包庫 方便理解技術原理 (一)
代碼執行個體地址:https://download.csdn.net/download/superwebmaster/10415730
探索技術的路上本應該自己造輪子,即使市面上有再多的選擇,自己動手嘗試也是必要的,第一次嘗試必然會問題眾多,但你不覺得解決他是一件很有成就感的事情嗎,這樣才能帶給你更大的進步和更深刻的領悟。
如果沒有寫過的並感興趣的不妨一起來實現一下這個簡單的爬蟲。
其實用golang實現爬蟲是很簡單是事情,但也分情況,我們這次的文章就分享一種最簡單的爬蟲實現方式,用到的官方庫如下:
import ( "fmt" "io" "io/ioutil" "net/http" "os" "regexp" "strconv" "strings" "time" )
如果你能單單通過這些庫就想到該怎麼做了,那你就很棒棒了。
為了讓程式能一直運行下去,我們首先要有一個源網頁,然後不斷爬抓記錄新的連結,記錄的手段有很多,比如存在資料庫、通過redis緩衝、存在文字檔,最簡單的應該就是存在資料庫了,這個看你們的技術偏向了。我打算把爬來的連結儲存在文字檔裡。
首先,瞭解自己爬抓的目標,我準備爬取所有的Golang相關答疑或者文章,然後翻來覆去很多網站都感覺不適合做源網址,然後靈機一動,百度一下
然後就用這樣作為源網址吧:百度一下 - Golang實現
有了源網址,那下面的事情只要捋順就好辦了。首先我們為了抓取到連結,需要一個Regex
var ( regHref = `((ht|f)tps?)://[w]{0,3}.baidu.com/link\?[a-zA-z=0-9-\s]*` )
因為這個Regex我們後面可能會複用,所以可以存到一個全域變數裡。
一個爬蟲如果不限制分秒爬抓次數,那你的網路肯定會受不了,如果電腦配置不行的話,電腦也會掛掉,所以我們需要寫一個計時器,golang已經提供了計時器的包 => time
func Timer() { t := time.NewTimer(time.Second * 1) <-t.C fmt.Print("\n\n\n執行爬抓\n\n") Timer() }
為什麼要寫在一個Timer函數裡?當然是用來調用的 /手動滑稽
因為我們存在兩種情況,第一次爬取或不是第一次爬取的情況是做不同操作的。那要怎麼判斷呢?因為我們的連結是儲存在txt檔案裡的,所以我們只需要去查txt檔案是不是為空白,如果為空白就認為他是第一次執行程式,先訪問源網址,否則就按照檔案裡的連結依次訪問。
代碼如下:
func main() { if checkFile("./data/", "url.txt").Size() == 0 { fistStart() main() } else { Timer() } }
那我們先看一下firstStart()函數,稍後再解釋代碼:
func fistStart() { var num int url := "http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=39042058_20_oem_dg&wd=golang%E5%AE%9E%E7%8E%B0&oq=golang%2520%25E5%2588%25A0%25E9%2599%25A4%25E6%2595%25B0%25E7%25BB%2584&rsv_pq=d9be28ec0002df1b&rsv_t=8017GWpSLPhDmKilZQ1StC04EVpUAeLEP90NIm%2Bk5pRh5R9o57NHMO8Gaxm1TtSOo%2FvtJj%2B98%2Fsc&rqlang=cn&rsv_enter=1&inputT=3474&rsv_sug3=16&rsv_sug1=11&rsv_sug7=100&rsv_sug2=0&rsv_sug4=4230" resp, _ := http.Get(url) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) reg := regexp.MustCompile(`((ht|f)tps?)://[w]{0,3}.baidu.com/link\?[a-zA-z=0-9-\s]*`) f, _ := os.OpenFile("./data/url.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) defer f.Close() for _, d := range reg.FindAllString(string(body), -1) { ff, _ := os.OpenFile("./data/url.txt", os.O_RDWR, 0666) file, _ := ioutil.ReadAll(ff) dd := strings.Split(d, "") dddd := "" for _, ddd := range dd { if ddd == "?" { ddd = `\?` } dddd += ddd } if checkRegexp(string(file), dddd, 0).(string) == "" { io.WriteString(f, d+"\n") fmt.Print("\n收集地址:" + d + "\n") num++ } // fmt.Print(string(file)) ff.Close() } fmt.Print("\n首次收集網路地址:" + strconv.Itoa(len(reg.FindAllString(string(body), -1))) + "\n") fmt.Print("\n去重後網路地址數:" + strconv.Itoa(num)) fmt.Print("\n\n首次儲存成功!\n") }
很抱歉,沒有注釋習慣
其實很簡單,就是發起一個get請求,然後你會擷取到byte[]類型的資料,轉換成string類型之後,就是網頁的代碼了。
分解一下(瞭解原理的跳過這段):
url := "http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=39042058_20_oem_dg&wd=golang%E5%AE%9E%E7%8E%B0&oq=golang%2520%25E5%2588%25A0%25E9%2599%25A4%25E6%2595%25B0%25E7%25BB%2584&rsv_pq=d9be28ec0002df1b&rsv_t=8017GWpSLPhDmKilZQ1StC04EVpUAeLEP90NIm%2Bk5pRh5R9o57NHMO8Gaxm1TtSOo%2FvtJj%2B98%2Fsc&rqlang=cn&rsv_enter=1&inputT=3474&rsv_sug3=16&rsv_sug1=11&rsv_sug7=100&rsv_sug2=0&rsv_sug4=4230" resp, _ := http.Get(url) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) reg := regexp.MustCompile(`((ht|f)tps?)://[w]{0,3}.baidu.com/link\?[a-zA-z=0-9-\s]*`) f, _ := os.OpenFile("./data/url.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) defer f.Close()
這段主要是發起一個get網路請求,然後把請求到的byte資料轉成stirng類型的資料,跳過正則擷取匹配連結擷取一個連結數組(不過分贅述,如果還不懂http請求可以另尋百度)
for _, d := range reg.FindAllString(string(body), -1) { ff, _ := os.OpenFile("./data/url.txt", os.O_RDWR, 0666) file, _ := ioutil.ReadAll(ff) dd := strings.Split(d, "") dddd := "" for _, ddd := range dd { if ddd == "?" { ddd = `\?` } dddd += ddd } if checkRegexp(string(file), dddd, 0).(string) == "" { io.WriteString(f, d+"\n") fmt.Print("\n收集地址:" + d + "\n") num++ } // fmt.Print(string(file)) ff.Close() }
通過迴圈數組,首先對連結裡的特殊符號做特出處理,然後通過checkRegexp函數做查重,就是防止有多個重複的連結記錄導致浪費資源,最後存入txt檔案。
checkRegexp函數:
func checkRegexp(cont string, reg string, style int) (result interface{}) { check := regexp.MustCompile(reg) switch style { case 0: result = check.FindString(cont) case 1: result = check.FindAllString(cont, -1) default: result = check.FindAll([]byte(cont), -1) } return }
這裡,程式的首次執行已經完成,並可以成功記錄爬取的連結了。程式執行如下:
下一篇繼續講如何通過這些記錄的連結過濾無用爬取有效內容,如果在上面的代碼中,還有疑問或發現驚天大Bug可以加我QQ625366394一起解決
469 次點擊 ∙ 1 贊