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之后便可运行

Copy
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") }
posted @   村口王铁匠  阅读(1216)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示

目录

目录

×