[初学者]学以致用,go小白写了一段爬虫

最近学习golang,感觉有点枯燥,于是写了一小段爬虫
使用到的库

github.com/antchfx/htmlquery
gorm.io/gorm
gorm.io/driver/mysql

初学者,还望大佬们指点

package main

import (
    "database/sql"
    "fmt"
    "github.com/antchfx/htmlquery"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
    "log"
    "os"
    "strconv"
    "strings"
    "sync"
    "time"
)

// 全局数据库对象
var db = &gorm.DB{}

// 数据库配置信息
var drive = "mysql"
var database = "golang"
var host = "127.0.0.1"
var port = 3306
var username = "root"
var password = "root"

// 协程
var wg sync.WaitGroup

func init() {
    // 连接数据库
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", username, password, host, port, database)
    mysqlDb, err := sql.Open(drive, dsn)
    if err != nil {
        panic(err)
    }
    db, err = gorm.Open(mysql.New(mysql.Config{
        Conn: mysqlDb,
    }), &gorm.Config{
        // 日志配置
        Logger: logger.New(
            log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
            logger.Config{
                SlowThreshold:             time.Second, // 慢 SQL 阈值
                LogLevel:                  logger.Info, // 日志级别
                IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
                Colorful:                  false,       // 禁用彩色打印
            }),
    })
    if err != nil {
        panic("数据库连接失败")
    }
    fmt.Println("数据库连接成功!")
}

// 文章
type Article struct {
    gorm.Model
    Title    string `json:"title"`
    CateId   int    `json:"cate_id"`
    Status   int    `json:"status"`
    Author   string `json:"author"`
    SiteName string `json:"site_name"`
    PushTime string `json:"push_time"`
    Content  string `json:"content"`
    Visit    int    `json:"visit"`
    Likes    int    `json:"likes"`
    UnLikes  int    `json:"un_likes"`
    Level    int    `json:"level"`
}

// 文章分类
type ArticleCate struct {
    Id        int    `json:"id"`
    Name      string `json:"name"`
    Sort      int    `json:"sort"`
    FromName  string `json:"from_name"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

// 获取文章分类
func getCateList(url string) (data []ArticleCate, err error) {
    doc, err := htmlquery.LoadURL(url)
    if err != nil {
        return nil, err
    }
    list := htmlquery.Find(doc, "//ul[@id='starlist']/li")
    var articleCate = []ArticleCate{}
    for _, item := range list {
        a := htmlquery.FindOne(item, "a")
        name := htmlquery.InnerText(a)

        if name != "百科网" && name != "生活知识" {
            cate := ArticleCate{
                Name:      name,
                FromName:  url + htmlquery.SelectAttr(a, "href"),
                CreatedAt: time.Now(),
                UpdatedAt: time.Now(),
            }
            articleCate = append(articleCate, cate)
        }
    }
    // 2、保存文章分类到数据库中
    db.Create(&articleCate)
    return articleCate, err
}

// 获取文章列表
func getArticleList(baseUrl, cateUrl, siteName string, cateId int) (data []Article, err error) {
    doc, err := htmlquery.LoadURL(cateUrl)
    if err != nil {
        return nil, err
    }
    list := htmlquery.Find(doc, "//div[@class='blogs-list']/ul/li")
    var articleList = []Article{}
    for _, item := range list {
        a := htmlquery.FindOne(item, "//h2/a")
        span := htmlquery.FindOne(item, "//span")
        article_time := htmlquery.InnerText(span)

        // 获取详情
        detailUrl := baseUrl + htmlquery.SelectAttr(a, "href")
        fmt.Println("详情地址:", detailUrl)
        detail, err := getArticleDetail(detailUrl)
        if err != nil {
            return nil, err
        }
        article := Article{
            Title:    htmlquery.InnerText(a),
            PushTime: article_time,
            Content:  detail,
            CateId:   cateId,
            SiteName: siteName,
        }
        articleList = append(articleList, article)
    }
    // 保存数据库
    db.Create(&articleList)
    return articleList, err
}

// 获取文章详情,并且保存数据库
func getArticleDetail(url string) (string, error) {
    doc, err := htmlquery.LoadURL(url)
    if err != nil {
        return "", err
    }
    content := htmlquery.FindOne(doc, "//div[@class='newstext']")
    // 保存数据库
    return htmlquery.OutputHTML(content, false), err
}

// 获取分页规则
func getPageRule(CateUrl string) (pre string, count int, err error) {
    doc, err := htmlquery.LoadURL(CateUrl)
    if err != nil {
        return "", 0, err
    }
    page := htmlquery.Find(doc, "//div[@class='pagelist']/a")
    fmt.Println(len(page), page[2])
    a := htmlquery.SelectAttr(page[2], "href")
    arr := strings.Split(a, "_")
    // 总数
    lastPage := htmlquery.SelectAttr(page[len(page)-1], "href")
    arr2 := strings.Split(lastPage, "_")
    stringTotal := strings.Split(arr2[2], ".")
    total, _ := strconv.Atoi(stringTotal[0])
    return fmt.Sprintf("%s_%s_", arr[0], arr[1]), total, err
}

// 开启爬取
func spider(baseUrl, name string, cate ArticleCate, count int, pageRule string) {
    if count > 0 {
        for page := 1; page <= count; page++ {
            // 获取文章列表
            articleListUrl := fmt.Sprintf("%s%s%d.html", cate.FromName, pageRule, page)
            fmt.Println("爬取地址:", articleListUrl)
            list, err := getArticleList(baseUrl, articleListUrl, name, cate.Id)
            if err != nil {
                panic(err)
            }
            // 保存数据库
            fmt.Println("列表", list)
        }
    }
    wg.Done()
}

func main() {
    baseUrl := "http://www.wenxue58.com"
    name := "词句百科网"
    // 1、 获取分类
    cateData, err := getCateList(baseUrl)
    if err != nil {
        panic(err)
    }

    var articleCate = []ArticleCate{}
    db.Where(articleCate).Order("id desc").Limit(len(cateData)).Find(&articleCate)
    for _, cate := range articleCate {
        // 获取分页规则
        fmt.Println("分类:", cate)
        pageRule, count, _ := getPageRule(cate.FromName)
        fmt.Println(pageRule, count, name)
        wg.Add(1)
        go spider(baseUrl, name, cate, count, pageRule)
    }
    wg.Wait()
    fmt.Println("爬取结束。。。")
}

好端端的写php为啥去学习go?
之前一直想用linux搞开发,可每次配置环境问题都很都疼,无意间接触到了docker,完美的解决了在linxu的各种复杂环境的配置,使用docker已经两年了,于是乎起心动念又开始折腾go了。
欢迎大家一起讨论:511300462
个人博客:doc.orangbus.cn

保持勇敢,坚持有趣,生命不息,折腾不止。
本帖已被设为精华帖!
本帖由系统于 2个月前 自动加精
OrangBus
讨论数量: 7

你好,请问一下go-sql-driver/mysql与go-gorm/mysql的区别是啥呢?

1个月前 评论
OrangBus (楼主) 1个月前
滚球兽进化 1个月前
_Ling (作者) 3周前
OrangBus (楼主) 2周前
_Ling (作者) 2周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!