• 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
    ", res)
    			file.Write(res)
    			file.WriteString("
    ")
    		case <- to.C:
    			flag = true
    			break
    		}
    	}
    	fmt.Println("end")
    }
    
    
  • 相关阅读:
    lua学习项目笔记
    Jenkins 安装、配置与项目新建及构建
    Gitlab的安装及项目新建
    PHP常见排序算法
    抽象类和接口的区别
    分布式版本控制系统Git的安装及使用
    深入解析OpenCart的代理类proxy
    PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式
    linux命令行传递参数定期执行PHP文件
    php类中的$this,static,const,self这几个关键字使用方法
  • 原文地址:https://www.cnblogs.com/liao-lin/p/11344863.html
Copyright © 2020-2023  润新知