Go语言Golang程序员

Golang 简单爬虫实现 · API接口开发

2018-02-11  本文已影响165人  ChainZhang

本文为转载,原文:Golang 简单爬虫实现 · API接口开发

爬虫

介绍

通过之前的实践,已经完成了小说内容定时爬取,以及小说内容的入库操作等。可是只有这些,我们还是看不了小说,因为它只在我们的数据库里。

那么今天,就简单的做几个api接口,将数据开放出来。这样只要调用api接口就能拿出数据展示了。这里面的api我就偷懒使用beego的库来实现了吧

我这边的api接口也不会太多,目前计划只做3个:

  1. 获取小说列表

  2. 获取指定小说章节列表

  3. 获取指定章节详情内容

实现

spider代码调整

由于我们的 main.go作为入口代码文件,所以,这边打算将之前的爬取数据的代码移到spider/spider.go文件中。
改版之后的spider.go代码如下:

package spider

import (
    "errors"

    "github.com/Chain-Zhang/igo/ilog"
    "github.com/Chain-Zhang/igo/conf"
    "github.com/robfig/cron"

    "ispider/models"
)

type SBook struct{
    Name string
    Image string
    Url string
    Chapters []*SChapter
}

type SChapter struct{
    Title string
    Url string
    Order int
    Pre int
    Next int
    Content string
}

type Spider interface{
    SpiderUrl(url string) error
}

func NewSpider(from string) (Spider, error){
    switch from{
    case "booktxt":
        return new(BookTextSpider), nil
    default:
        return nil, errors.New("系统暂未处理该类型的配置文件")
    }
}

func Start(){
    ilog.AppLog.Info("service start")
    c := cron.New()
    spec := conf.AppConfig.GetString("task.spec")
    ilog.AppLog.Info("spec: ",spec)
    c.AddFunc(spec,getBook)
    c.Start()
    select{}
}

func getBook(){
    ilog.AppLog.Info("spider start")
    books, _ := models.GetBookList("status", 1)
    for _, book := range books{
        go func(book *models.Book){
            s, err := NewSpider(book.From)
            if err != nil{
                ilog.AppLog.Error("new Spider error: ", err.Error())
                return
            }
            err = s.SpiderUrl(book.Url)
            if err != nil{
                ilog.AppLog.Error("new Document error: ", err.Error())
            }
            ilog.AppLog.Info(book.Name, "已爬取完毕")
        }(book)
    }
}

api文件列表

既然使用了beego的库,那么,就在原有的目录基础上先建一些相关的目录和文件吧

controllers  //controllers包
----base.go  //controller基类简单封装
----book.go  //book的controller实现

routers      //routers包
----router.go //路由分配,

main.go  //入口代码文件

没错,我们的api接口实现就是这么几个文件就能搞定。

代码实现

main.go

main.go文件作为入口文件,所以这里写的并不复杂,只需要调用2个函数,以及初始化路由即可。代码如下:

package main

import (
    _ "ispider/routers"  //执行routers包的init函数
    "ispider/spider"
    "github.com/astaxie/beego"
    "github.com/Chain-Zhang/igo/ilog"
)

func main() {
    ilog.AppLog.Info("start")
    go spider.Start()   //异步执行爬虫协程
    beego.Run(":8089")  //开启api服务
}

controllers

base.go

base.go作为所有controllers的基类,所以需要封装一下公用的函数,提高代码复用率。

package controllers

import(
    "github.com/astaxie/beego"
)

// json 返回错误码
const (
    MSG_OK  = 0   // 成功
    MSG_ERR = -1  // 失败
)

// 基类
type BaseController struct{
    beego.Controller
}

// 固定返回的json数据格式
// msgno: 错误码
// msg: 错误信息
// data: 返回数据
func (self *BaseController) toJson (msgno int, msg string, data interface{}){
    out := make(map[string]interface{})
    out["status"] = msgno
    out["msg"] = msg
    out["data"] = data
    self.Data["json"] = out
    self.ServeJSON()
}

从代码中可知,目前基类中只实现了一个格式化输出json的功能。
其他功能以后待扩展。

book.go

book.go就是针对小说的一个控制器了。代码如下:

package controllers

import(
    "ispider/models"
)

type BookController struct{
    BaseController
}

//获取小说列表
func (self *BookController) GetAll(){
    books, _ := models.GetBookList()
    self.toJson(MSG_OK, "成功", books)
}

// 分页获取指定小说的章节列表, 每页10条
// url参数:bookid => 小说id; page => 页码
func (self *BookController) GetChapters(){
    bookid, err := self.GetInt("bookid")
    if err != nil{
        self.toJson(MSG_ERR, err.Error(), nil)
    }
    page, err := self.GetInt("page")
    if err != nil{
        self.toJson(MSG_ERR, err.Error(), nil)
    }
    chapters, _ := models.GetChapterPage(page, 10, "book_id",bookid)
    self.toJson(MSG_OK, "success", chapters)
}

// 获取指定章节详细信息
// url参数: id => 章节id
func (self *BookController) GetChapter(){
    id, err := self.GetInt("id")
    if err != nil{
        self.toJson(MSG_ERR, err.Error(), nil)
    }
    chapter, err := models.GetChapterById(id)
    if err != nil{
        self.toJson(MSG_ERR, err.Error(), nil)
    }
    self.toJson(MSG_OK, "success", chapter)
}

从代码中可知,这个controller也比较简单,总共实现了之前所说的三个api接口的action。具体可见代码注释。

routers

既然controllers已经完成。那么接下来就是进行路由配置了。

package routers

import(
    "github.com/astaxie/beego"
    "ispider/controllers"
)

func init() {
    ns := beego.NewNamespace("/v1",
        beego.NSNamespace("/book",
            // /v1/book  获取小说列表
            beego.NSRouter("/", &controllers.BookController{}, "get:GetAll"),
            // /v1/book/getchapters?bookid=xxx&page=1  获取小说章节列表
            beego.NSRouter("/getchapters", &controllers.BookController{}, "get:GetChapters"),
            // /v1/book/chapter?id=xxx  获取章节内容
            beego.NSRouter("/chapter", &controllers.BookController{}, "get:GetChapter"),
        ),
    )
    beego.AddNamespace(ns)
}

好啦,如今路由耶配合了,那么,这编码也就结束了。

运行测试

接下来就是见证奇迹的时刻了。跑起来看看吧。

控制台进入代码根目录,执行命令bee run:

bee run

然后浏览器输入地址:http://localhost:8089/v1/book

小说列表

在输入地址:http://localhost:8089/v1/book/getchapters?bookid=2&page=5

章节列表

再输入章节详情的url: http://localhost:8089/v1/book/chapter?id=950

章节详情

源码

本文源码

转载请注明出处:
Golang 简单爬虫实现 · API接口开发

上一篇下一篇

猜你喜欢

热点阅读