Golang 簡單爬蟲實(shí)現(xiàn) · 定時(shí)任務(wù)

本文為轉(zhuǎn)載案铺,原文:Golang 簡單爬蟲實(shí)現(xiàn) · 定時(shí)任務(wù)

爬蟲

介紹

通過前一篇文章,我們已經(jīng)實(shí)現(xiàn)了簡單的爬蟲梆靖,爬取小說控汉。但是仔細(xì)思考,可以發(fā)現(xiàn)返吻,有很多缺陷姑子。

第一,我們爬取的地址是寫死的测僵,如果再想爬一本其他的書街佑,豈不是還有修改代碼?這樣很明顯是不合理的捍靠。

第二沐旨,對(duì)于連載的小說,我們不知道什么時(shí)候會(huì)有更新榨婆,所以磁携,我們也不知道什么時(shí)候去執(zhí)行這個(gè)爬取的任務(wù),而且還全都是手動(dòng)執(zhí)行

那么良风,今天就先針對(duì)這2個(gè)問題來說明下颜武。

思路

  1. 對(duì)于第一個(gè)問題,其實(shí)很簡單啦拖吼,只要改一改數(shù)據(jù)庫,然后將待爬取的任務(wù)都存到數(shù)據(jù)庫里这吻,然后查出來遍歷爬取數(shù)據(jù)即可吊档。

  2. 對(duì)于第二個(gè)問題,也不復(fù)雜唾糯。只需要搞個(gè)死循環(huán)怠硼,讓程序一直執(zhí)行鬼贱,而爬取數(shù)據(jù)的任務(wù),隔一段時(shí)間跑一次即可香璃。在這里我用了個(gè)第三方的包來做這件事:github.com/robfig/cron

實(shí)現(xiàn)

下面就前面的2個(gè)問題这难,及解決思路,來分別實(shí)現(xiàn)葡秒。

圖書配置

首先姻乓,要修改數(shù)據(jù)結(jié)構(gòu),在原有的book變中新增以下from, url, status眯牧。
修改后的結(jié)構(gòu)如下圖:

數(shù)據(jù)庫結(jié)構(gòu)

新增字段的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 - 已完結(jié)蹋岩;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;

具體字段的含義,可見注釋学少。

然后要做的就是將數(shù)據(jù)庫里的內(nèi)容查出來剪个,然后遍歷爬取即可

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)
    }
}

這樣,只要數(shù)據(jù)庫book表中有的數(shù)據(jù)版确,且為連載的書扣囊,就會(huì)被爬取了。第一個(gè)問題也就解決了绒疗。

定時(shí)任務(wù)

接下來就是如何實(shí)現(xiàn)定時(shí)爬取任務(wù)了侵歇。之前提到了第三方包:cron

cron

cron(計(jì)劃任務(wù))忌堂,顧名思義盒至,按照約定的時(shí)間,定時(shí)的執(zhí)行特定的任務(wù)(job)士修。cron 表達(dá)式 表達(dá)了這種約定

cron 表達(dá)式

cron 表達(dá)式代表了一個(gè)時(shí)間集合枷遂,使用 6 個(gè)空格分隔的字段表示。

字段名 是否必須 允許的值 允許的特定字符
秒(Seconds) 是 0-59
* / , -
分(Minutes) 是 0-59
* / , -
時(shí)(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)字段的值不區(qū)分大小寫棋嘲,如:SUN酒唉、Sun 和 sun 是一樣的。
2)星期

(Day of week)字段如果沒提供沸移,相當(dāng)于是 *

特殊符號(hào)說明

  1. 星號(hào)(*)
    表示 cron 表達(dá)式能匹配該字段的所有值痪伦。如在第5個(gè)字段使用星號(hào)(month),表示每個(gè)月

  2. 斜線(/)
    表示增長間隔雹锣,如第1個(gè)字段(minutes) 值是 3-59/15网沾,表示每小時(shí)的第3分鐘開始執(zhí)行一次,之后每隔 15 分鐘執(zhí)行一次(即 3蕊爵、18辉哥、33、48 這些時(shí)間點(diǎn)執(zhí)行),這里也可以表示為:3/15

  3. 逗號(hào)(,)
    用于枚舉值醋旦,如第6個(gè)字段值是 MON,WED,FRI恒水,表示 星期一、三饲齐、五 執(zhí)行

  4. 連字號(hào)(-)
    表示一個(gè)范圍钉凌,如第3個(gè)字段的值為 9-17 表示 9am 到 5pm 直接每個(gè)小時(shí)(包括9和17)

  5. 問號(hào)(?)
    只用于 日(Day of month) 和 星期(Day of week),表示不指定值捂人,可以用于代替 *

cron表達(dá)式示例

spec1 := "*/5 * * * * 御雕?" //每5秒執(zhí)行一次
spec2 := "0 */5 * * * ?"  //每5分鐘執(zhí)行一次
spec3 := "0 0 * * * ?"    //沒小時(shí)執(zhí)行一次
spec3 := "0 0 2 * * ?"    //每天凌晨2點(diǎn)執(zhí)行
spec4 := "0 0 2 1 * ?"    //每月1號(hào)的凌晨2點(diǎn)執(zhí)行
spec5 := "0 0 2 ? * mon,wed,fri" //每周一,三先慷,五凌晨2點(diǎn)執(zhí)行
spec6 := "0 12-59/5 * * * ?" //每小時(shí)的12分鐘之后饮笛,每5分鐘執(zhí)行一次

實(shí)例

介紹完表達(dá)式,就簡單的來個(gè)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{}
}
結(jié)果

目前為止论熙,corn的基本使用應(yīng)該沒有問題了福青。更深次的可以多看下源碼。

spider中的使用

既然前面已經(jīng)學(xué)會(huì)了cron的使用脓诡,后面就簡單了无午,先在配置文件中加一個(gè)corn表達(dá)式的配置:

[task]
spec = 0 */5 * * * ?  //每5分鐘執(zhí)行一次

使用配置的方式,會(huì)更加靈活一點(diǎn)祝谚。
然后就是項(xiàng)目中的實(shí)際使用了:

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)
    }
}

運(yùn)行一段時(shí)間后宪迟,日志中記載的內(nèi)容如下:


日志

當(dāng)然嘍,數(shù)據(jù)庫中的數(shù)據(jù)肯定不會(huì)少的啦交惯。

目前為止次泽,我的這個(gè)小爬蟲基本已經(jīng)完成了,剩下的就是對(duì)于可能遇到的站點(diǎn)的擴(kuò)展了席爽。當(dāng)然代碼里也早已經(jīng)留好了接口意荤,當(dāng)時(shí)候擴(kuò)展的話也會(huì)很容易的。

萬事俱備只锻,只欠一個(gè)前端了玖像。后面會(huì)持續(xù)跟進(jìn),屆時(shí)可以做成wap站齐饮,畢竟用手機(jī)看小說是多數(shù)情況的啦捐寥。

源碼

本文源碼

轉(zhuǎn)載請(qǐng)注明出處:
Golang 簡單爬蟲實(shí)現(xiàn) · 定時(shí)任務(wù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祖驱,隨后出現(xiàn)的幾起案子握恳,更是在濱河造成了極大的恐慌,老刑警劉巖捺僻,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乡洼,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)就珠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來醒颖,“玉大人妻怎,你說我怎么就攤上這事∨⑶福” “怎么了逼侦?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腰耙。 經(jīng)常有香客問我榛丢,道長,這世上最難降的妖魔是什么挺庞? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任晰赞,我火速辦了婚禮,結(jié)果婚禮上选侨,老公的妹妹穿的比我還像新娘掖鱼。我一直安慰自己,他們只是感情好援制,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布戏挡。 她就那樣靜靜地躺著,像睡著了一般晨仑。 火紅的嫁衣襯著肌膚如雪褐墅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天洪己,我揣著相機(jī)與錄音妥凳,去河邊找鬼。 笑死码泛,一個(gè)胖子當(dāng)著我的面吹牛猾封,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播噪珊,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼晌缘,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了痢站?” 一聲冷哼從身側(cè)響起磷箕,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阵难,沒想到半個(gè)月后岳枷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年空繁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了殿衰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盛泡,死狀恐怖闷祥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情傲诵,我是刑警寧澤凯砍,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站拴竹,受9級(jí)特大地震影響悟衩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜栓拜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一座泳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菱属,春花似錦钳榨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烦绳。三九已至奋蔚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姻氨,已是汗流浹背蝙搔。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工缕溉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吃型。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓证鸥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親勤晚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枉层,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容