本文为转载,原文:Golang 简单爬虫实现 · 定时任务
爬虫
介绍
通过前一篇文章,我们已经实现了简单的爬虫,爬取小说。但是仔细思考,可以发现,有很多缺陷。
第一,我们爬取的地址是写死的,如果再想爬一本其他的书,岂不是还有修改代码?这样很明显是不合理的。
第二,对于连载的小说,我们不知道什么时候会有更新,所以,我们也不知道什么时候去执行这个爬取的任务,而且还全都是手动执行
那么,今天就先针对这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)字段如果没提供,相当于是 *
特殊符号说明
星号(*)
表示 cron 表达式能匹配该字段的所有值。如在第5个字段使用星号(month),表示每个月斜线(/)
表示增长间隔,如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15逗号(,)
用于枚举值,如第6个字段值是 MON,WED,FRI,表示 星期一、三、五 执行连字号(-)
表示一个范围,如第3个字段的值为 9-17 表示 9am 到 5pm 直接每个小时(包括9和17)问号(?)
只用于 日(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 mainimport ( "time" "fmt" "github.com/robfig/cron")var i = 0func 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 mainimport ( "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 简单爬虫实现 · 定时任务
共同学习,写下你的评论
评论加载中...
作者其他优质文章