golang爬虫 高并发抓取阳光高考招生简章

golang爬虫高并发抓取阳光高考招生简章

链接地址

一级页面 学校列表
https://gaokao.chsi.com.cn/zsgs/zhangcheng/listVerifedZszc--method-index,lb-1,start-0.dhtml

二级页 招生简章列表
https://gaokao.chsi.com.cn/zsgs/zhangcheng/listZszc--schId-5.dhtml

三级页 招生章程内容
https://gaokao.chsi.com.cn/zsgs/zhangcheng/listVerifedZszc--infoId-2708104715,method-view,schId-5.dhtml

抓取流程

在这里插入图片描述

抓取框架 gathertool

框架地址: https://github.com/mangenotwork/gathertool
框架下载: go get github.com/mangenotwork/gathertool
介绍: 轻量级爬虫,接口测试,压力测试框架, 提高开发对应场景的golang程序。
框架文档: https://380949.baklib-free.com/

实现

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/PuerkitoBio/goquery"
    gt "github.com/mangenotwork/gathertool"
)

var (
    PG1Queue = gt.NewQueue() // 一级页面抓取任务队列
    PG2Queue = gt.NewQueue() // 二级页面抓取任务队列
    PG3Queue = gt.NewQueue() // 三级页面抓取任务队列
    host = "127.0.0.1"
    port = 3306
    user = "root"
    password = "root123"
    database = "spider"
    tableName = "yggk_zszc_1"
)

func init(){
    gt.NewMysqlDB(host, port, user, password, database)
    err := gt.MysqlDB.Conn()
    if err != nil{
        log.Panic("数据库初始化失败")
    }
    //初始化表
    gt.MysqlDB.NewTable(tableName, map[string]string{
        "school_name": "varchar(30)",
        "zszcName" : "varchar(50)",
        "fbTime" : "varchar(30)",
        "url" : "varchar(200)",
        "content": "text",
    })
}

// 全量抓取
func main(){
    // 一共 29页
    for p:=0; p<30;p++{
        pg1 := "https://gaokao.chsi.com.cn/zsgs/zhangcheng/listVerifedZszc--method-index,lb-1,start-%d.dhtml"
        PG1Queue.Add(&gt.Task{
            Url: fmt.Sprintf(pg1, p*100),
        })
    }
    //并发执行一级页面
    gt.StartJobGet(50,PG1Queue,
        gt.SucceedFunc(Pg1Succeed),//请求成功后执行的方法
        gt.RetryFunc(Retry),
        gt.FailedFunc(Fail),
    )
    log.Println(" 并发执行一级页面 完成")
    //并发执行二级页面
    gt.StartJobGet(50,PG2Queue,
        gt.SucceedFunc(Pg2Succeed),//请求成功后执行的方法
        gt.RetryFunc(Retry),
        gt.FailedFunc(Fail),
    )
    log.Println(" 并发执行二级页面 完成")
    //并发执行三级页面
    gt.StartJobGet(100,PG3Queue,
        gt.SucceedFunc(Pg3Succeed),//请求成功后执行的方法
        gt.RetryFunc(Retry),
        gt.FailedFunc(Fail),
    )
    log.Println(" 并发执行三级页面 完成")

    ////测试第二级页面
    //c,_ := gt.Get("https://gaokao.chsi.com.cn/zsgs/zhangcheng/listZszc--schId-1.dhtml",
    //  gt.SucceedFunc(Pg2Succeed))
    //c.Do()

    //测试第三级页面
    //for i:=0; i<100;i++{
    //  go func(){
    //      c,_ := gt.Get("https://gaokao.chsi.com.cn/zsgs/zhangcheng/listVerifedZszc--infoId-2697675279,method-view,schId-1.dhtml",
    //          gt.SucceedFunc(Pg3Succeed))
    //      c.Do()
    //  }()
    //}
    //time.Sleep(10*time.Second)
}

// 抓取第一级页面成功后
func Pg1Succeed(ctx *gt.Context){
    html := string(ctx.RespBody)
    dom,err := gt.NewGoquery(html)
    if err != nil{
        log.Println(err)
        return
    }
    result := dom.Find("table tbody")
    if len(result.Nodes) < 2{
        log.Println("没有找到table")
    }
    result.Eq(1).Each(func(i int, tr *goquery.Selection){
        tr.Find("td").Each(func(i int, td *goquery.Selection){
            schoolName := td.Text()
            href,_ := td.Find("a").Attr("href")
            log.Println(schoolName, href)
            // 加入二级页面队列
            PG2Queue.Add(&gt.Task{
                Url: "https://gaokao.chsi.com.cn/" + href,
                Data: map[string]interface{}{
                    "school_name":schoolName,
                },
            })
        })
    })
}
// 抓取第二级页面成功后
func Pg2Succeed(ctx *gt.Context){
    html := string(ctx.RespBody)
    dom,err := gt.NewGoquery(html)
    if err != nil{
        log.Println(err)
        return
    }
    result := dom.Find(".zszcdel table tbody")
    //log.Println(result.Html())
    result.Find("tr").Each(func(i int, tr *goquery.Selection){
        td := tr.Find("td")
        zszcName := td.Eq(0).Text()
        href,_ := td.Eq(0).Find("a").Attr("href")
        fbTime := td.Eq(1).Text()
        log.Println(zszcName, href, fbTime)
        ctx.Task.Data["zszcName"] = zszcName
        ctx.Task.Data["fbTime"] = fbTime
        ctx.Task.Data["url"] = "https://gaokao.chsi.com.cn/" + href
        ctx.Task.Url = "https://gaokao.chsi.com.cn/" + href
        PG3Queue.Add(ctx.Task)
    })
}
// 抓取第二级页面成功后
func Pg3Succeed(ctx *gt.Context){
    html := string(ctx.RespBody)
    //log.Println(html)
    dom,err := gt.NewGoquery(html)
    if err != nil{
        log.Println(err)
        return
    }
    content,err := dom.Find(".content").Html()
    log.Println(content, err)
    if err != nil || content == ""{
        log.Println("还给队列")
        PG3Queue.Add(ctx.Task)
    }
    // 写入数据库
    schoolName := gt.StringValue(ctx.Task.Data["school_name"]) // 转换成字符串
    zszcName := gt.StringValue(ctx.Task.Data["zszcName"])
    fbTime := gt.StringValue(ctx.Task.Data["fbTime"])
    err = gt.MysqlDB.Insert(tableName, map[string]interface{}{
        "school_name": gt.CleaningStr(schoolName), // 清理字符串前后空格和换行符等
        "zszcName" : gt.CleaningStr(zszcName),
        "fbTime" : gt.CleaningStr(fbTime),
        "url" : ctx.Task.Data["url"],
        "content": content,
    })
    log.Println(err)
}

func Retry(*gt.Context){
    time.Sleep(2*time.Second)
}
func Fail(ctx *gt.Context){
    log.Println(ctx.Err)
}

结果

在这里插入图片描述
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容