Golang 简单爬虫实现 · 定时任务

本文为转载,原文:Golang 简单爬虫实现 · 定时任务

爬虫

介绍

通过前一篇文章,我们已经实现了简单的爬虫,爬取小说。但是仔细思考,可以发现,有很多缺陷。

第一,我们爬取的地址是写死的,如果再想爬一本其他的书,岂不是还有修改代码?这样很明显是不合理的。

第二,对于连载的小说,我们不知道什么时候会有更新,所以,我们也不知道什么时候去执行这个爬取的任务,而且还全都是手动执行

那么,今天就先针对这2个问题来说明下。

思路

  1. 对于第一个问题,其实很简单啦,只要改一改数据库,然后将待爬取的任务都存到数据库里,然后查出来遍历爬取数据即可。

  2. 对于第二个问题,也不复杂。只需要搞个死循环,让程序一直执行,而爬取数据的任务,隔一段时间跑一次即可。在这里我用了个第三方的包来做这件事:github.com/robfig/cron

实现

下面就前面的2个问题,及解决思路,来分别实现。

图书配置

首先,要修改数据结构,在原有的book变中新增以下from, url, status
修改后的结构如下图:

数据库结构

新增字段的sql语句如下:

-- MySQL Workbench Synchronization
-- Generated: 2018-02-07 16:50
-- Model: New Model
-- Version: 1.0
-- Project: Name of the project
-- Author: chain
-- Comment: Update book

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

ALTER TABLE `chain_book`.`book` 
ADD COLUMN `status` INT(11) NULL DEFAULT NULL COMMENT '0 - 已完结;1 - 连载中' AFTER `image`,
ADD COLUMN `from` VARCHAR(100) NULL DEFAULT NULL COMMENT '源站' AFTER `status`,
ADD COLUMN `url` VARCHAR(100) NULL DEFAULT NULL COMMENT '源站地址' AFTER `from`;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

具体字段的含义,可见注释。

然后要做的就是将数据库里的内容查出来,然后遍历爬取即可

func GetBook(){
    ilog.AppLog.Info("spider start")
    books, _ := models.GetBookList("status", 1)
    for _, book := range books{
        go func(book *models.Book){
            s, err := spider.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)
    }
}

这样,只要数据库book表中有的数据,且为连载的书,就会被爬取了。第一个问题也就解决了。

定时任务

接下来就是如何实现定时爬取任务了。之前提到了第三方包:cron

cron

cron(计划任务),顾名思义,按照约定的时间,定时的执行特定的任务(job)。cron 表达式 表达了这种约定

cron 表达式

cron 表达式代表了一个时间集合,使用 6 个空格分隔的字段表示。

字段名 是否必须 允许的值 允许的特定字符
秒(Seconds) 是 0-59
* / , -
分(Minutes) 是 0-59
* / , -
时(Hours) 是 0-23
* / , -
日(Day of month) 是 1-31
* / , – ?
月(Month) 是 1-12 or JAN-DEC
* / , -
星期(Day of week) 否 0-6 or SUM-SAT
* / , – ?

注:

1)月(Month)和星期(Day of week)字段的值不区分大小写,如:SUN、Sun 和 sun 是一样的。
2)星期

(Day of week)字段如果没提供,相当于是 *

特殊符号说明

  1. 星号(*)
    表示 cron 表达式能匹配该字段的所有值。如在第5个字段使用星号(month),表示每个月

  2. 斜线(/)
    表示增长间隔,如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15

  3. 逗号(,)
    用于枚举值,如第6个字段值是 MON,WED,FRI,表示 星期一、三、五 执行

  4. 连字号(-)
    表示一个范围,如第3个字段的值为 9-17 表示 9am 到 5pm 直接每个小时(包括9和17)

  5. 问号(?)
    只用于 日(Day of month) 和 星期(Day of week),表示不指定值,可以用于代替 *

cron表达式示例

spec1 := "*/5 * * * * ?" //每5秒执行一次
spec2 := "0 */5 * * * ?"  //每5分钟执行一次
spec3 := "0 0 * * * ?"    //没小时执行一次
spec3 := "0 0 2 * * ?"    //每天凌晨2点执行
spec4 := "0 0 2 1 * ?"    //每月1号的凌晨2点执行
spec5 := "0 0 2 ? * mon,wed,fri" //每周一,三,五凌晨2点执行
spec6 := "0 12-59/5 * * * ?" //每小时的12分钟之后,每5分钟执行一次

实例

介绍完表达式,就简单的来个corn的小例子吧

package main

import (
    "time"
    "fmt"
    "github.com/robfig/cron"
)
var i = 0

func main() {
    fmt.Println("start ")
    c := cron.New()
    spec := "*/5 * * * * ?"
    c.AddFunc(spec,func(){
        i ++
        fmt.Println(time.Now(), "cron running: ", i)
    })
    c.Start()
    select{}
}
结果

目前为止,corn的基本使用应该没有问题了。更深次的可以多看下源码。

spider中的使用

既然前面已经学会了cron的使用,后面就简单了,先在配置文件中加一个corn表达式的配置:

[task]
spec = 0 */5 * * * ?  //每5分钟执行一次

使用配置的方式,会更加灵活一点。
然后就是项目中的实际使用了:

package main

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

    "ispider/spider"
    "ispider/models"
)

func main() {
    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 := spider.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)
    }
}

运行一段时间后,日志中记载的内容如下:


日志

当然喽,数据库中的数据肯定不会少的啦。

目前为止,我的这个小爬虫基本已经完成了,剩下的就是对于可能遇到的站点的扩展了。当然代码里也早已经留好了接口,当时候扩展的话也会很容易的。

万事俱备,只欠一个前端了。后面会持续跟进,届时可以做成wap站,毕竟用手机看小说是多数情况的啦。

源码

本文源码

转载请注明出处:
Golang 简单爬虫实现 · 定时任务

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容