go爬蟲之爬取豆瓣電影


go爬取豆瓣電影

好久沒使用go語言做個項目了,上午閑來無事花了點時間使用golang來爬取豆瓣top電影,這里我沒有用colly框架而是自己設計簡單流程。mark一下

思路

定義兩個channel,一個channel存放web網頁源內容,另一個存放提取后的有效內容。

多個goroutine並發爬取網頁源內容放到存放web網頁的channel里,再啟動goroutine去存放web網頁的channel里讀取內容,讀取到內容后啟動goroutine去提取有效值存放到channel里,最后持久化寫入本地文件(文件寫操作並非線程安全所以這里我沒有使用多goroutine)。

代碼

具體代碼如下,如果想執行看效果需要go get github.com/PuerkitoBio/goquery安裝三方包或者直接點這里拉取代碼設置GOPATH之后便可運行

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
	"time"
	"os"

	"github.com/PuerkitoBio/goquery"
)

/*
通過多個goroutine並發執行爬取操作,channel存放要爬取url內容和爬取結果
這樣只需要設計爬取函數和提取函數
*/

func get_web_content(url string, chan_web chan string) {
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("http get error", err)
		return
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("read error", err)
		return
	}
	chan_web <- string(body)
}

func extract_valid_content(body string, chan_r chan []byte) {
	dom, err := goquery.NewDocumentFromReader(strings.NewReader(body))
	if err != nil {
		fmt.Println(err)
	}
	dom.Find("ol.grid_view div.item").Each(func(i int, selection *goquery.Selection) {
		// extract result
		result := make(map[string]string)
		name := selection.Find("div.info span.title").First().Text()
		doctor_str := selection.Find("div.info div.bd p").First().Text()
		r := regexp.MustCompile(`導演:(?s:(.*?))(主演|主|&|\.\.\.)`)
		doctor := r.FindAllStringSubmatch(doctor_str, -1)[0][1]
		rating_num := selection.Find("div.star span.rating_num").First().Text()
		evaluation_str := selection.Find("div.star span").Last().Text()
		r = regexp.MustCompile(`(?s:(.*?))人評價`)
		evaluation := r.FindAllStringSubmatch(evaluation_str, -1)[0][1]
		ranking := selection.Find("div.pic em").First().Text()
		result["name"] = name
		result["doctor"] = doctor
		result["rating_num"] = rating_num
		result["evaluation"] = evaluation
		result["ranking"] = ranking
		json_str, err := json.Marshal(result)
		if err != nil {
			fmt.Println(err)
			return
		}
		chan_r <- json_str
	})
}

func main() {
	var (
		OutputFile = "./film_crawl.txt"
	)
	base_url := "https://movie.douban.com/top250?start=%d&filter="
	chan_web_content := make(chan string)
	defer close(chan_web_content)
	chan_r := make(chan []byte)
	defer close(chan_r)
	for i := 0; i < 10; i++ {
		url := fmt.Sprintf(base_url, i*25)
		go get_web_content(url, chan_web_content)
	}

	go func() {
		for {
			web_content, ok := <- chan_web_content
			if !ok {
				break
			}
			go extract_valid_content(web_content, chan_r)
		}
	}()

	flag := false
	to := time.NewTimer(time.Second * 5)
	file, err := os.OpenFile(OutputFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("Failed to open the file", err.Error())
		return
	}
	defer file.Close()
	for {
		if flag {
			break
		}
		to.Reset(time.Second * 5)
		select {
		case res := <- chan_r:
			fmt.Printf("%s\n", res)
			file.Write(res)
			file.WriteString("\n")
		case <- to.C:
			flag = true
			break
		}
	}
	fmt.Println("end")
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM