iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
2
Everything on Azure

三十天.NET❤️Azure漸進式開發專案系列 第 14

三十天.NET與Azure漸進式開發專案(14): Timer Trigger排程抓資料保存到Azure SQL DataBase

2018-10-20.14.38.42-image.png


前篇文章版本有個缺點:每一次網頁運行會重新抓取一次網頁內容,假如做成固定時間爬取一次網頁,接著把資料存到資料庫,這樣才可以避免重複行為的浪費

要達到目的,可以利用 Timer Trigger 做一個輕量級排程器,把整理後的資料保存到前面介紹的 Azure SQL Database ,方便之後使用SQL篩選查詢資料。


建立Timer Trigger

新增/現有Azure Function > 函式 > 點擊 Timer Trigger 圖案 > 填寫名稱、排程時間 > 建立
2018-10-19.23.13.23-image.png
2018-10-19.23.10.36-image.png

建立預設自帶一個Log小程式,可以點擊執行做線上測試。
2018-10-19.23.09.48-image.png

運行週期可以在function.json - schedule欄位做修改,使用CRON指定時間區間,不熟悉的讀者可以到線上工具Online Cron了解,舉例0 0/15 * 1/1 * ? *代表每15分鐘跑一次
2018-10-19.23.10.00-image.png

在線上開發雖然輕便、方便,但是也造成開發的麻煩,像是提示系統、檔案管理、動作緩慢問題。

這時候我們可以使用Azure Function提供下載線上專案的功能,轉成VS方案在自己的電腦打開編輯。

方式點選Function > 概觀 > 下載應用程式內容 > 選擇下載內容與Visual Studio專案
2018-10-19.23.08.54-image.png

這邊記得要勾選包含應用程式設定,否則本機環境無法運行,如圖片
2018-10-19.23.08.33-image.png
2018-10-19.23.08.38-image.png

下載完解壓縮,可以看到熟悉的.csproj專案檔,我們只需要
2018-10-19.23.08.16-image.png
2018-10-19.23.08.13-image.png

專案結構跟線上結構一樣。
2018-10-19.23.07.53-image.png

可以在本機運行、測試 TimerTrigger 真是方便又酷炫!
2018-10-19.23.07.36-image.png


編寫程式

【第一步】藉由VO類別為原型設計資料庫表格,簡單在Azure SQL DataBase設計IT鐵人賽文章的表格

 public class Post
{
    public string Title { get; set; }
    public string link { get; set; }
    public string Content { get; set; }
    public string Article { get; set; }
    public DateTime PubDate { get; set; }
}
CREATE TABLE [ITIronPost](
	[Title] [nvarchar](250) NOT NULL,
	[link] [nvarchar](250) NOT NULL,
	[Content] [nvarchar](max) NULL,
	[Article] [nvarchar](250) NOT NULL,
	[PubDate] [datetime] NOT NULL,
 CONSTRAINT [PK_ITIronPost] PRIMARY KEY CLUSTERED 
(
	[link] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

接著複製連線字串貼到程式的connectionstring
2018-10-19.23.06.38-image.png

【第二步】T-SQL以連結為PK主鍵,判斷資料有沒有存在,假如沒有存在已有資料做新增動作;假如有資料做更新資料動作。

if(exists(select top 1 1 from [ITIronPost] where [link] = @link )) begin  
     update [ITIronPost] SET [Title] = @Title,[Content] = @Content ,[Article] = @Article ,[PubDate] = @PubDate WHERE [link] = @link;  
end  
else begin  
     INSERT INTO [ITIronPost] ([Title] ,[link] ,[Content] ,[Article] ,[PubDate]) VALUES (@Title,@link,@Content,@Article,@PubDate) ;
end  

【第三步】將爬蟲、保存DB資料動作封裝到Execute方法,由TimmerTrigger Run方法裡呼叫。

public static void Run(TimerInfo myTimer, ILogger log)  
{  
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 
    
    Execute(); /*呼叫爬蟲、保存DB資料動作*/ 
}  

【最後】更新IT鐵人賽文章到Azure SQL DataBase的完整程式

public static void Run(TimerInfo myTimer, ILogger log)  
{  
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 
    
    Execute();  
}  

/*
  使用Library
  - Dapper 處理SQL
  - AngelSharp 處理網頁DOM
*/
//將爬蟲、保存DB資料動作封裝到`Execute`方法
public static void Execute()  
{  
    const string connectionString = @"AzureDB連接";  
    const string userid = "20105988";  
    const string articleid = "1622";  
    var itironman = ITIronManSyncPostService.GetITIronManPosts($"https://ithelp.ithome.com.tw/users/{userid}/ironman/{articleid}");  
    var posts = itironman.Result.Posts;  
  
    using (var conn = GetOpenConnection())  
    using (var tsx = new TransactionScope())  
    {  
        conn.Execute(@"  
                if(exists(select top 1 1 from [ITIronPost] where [link] = @link )) begin  
                     update [ITIronPost] SET [Title] = @Title,[Content] = @Content ,[Article] = @Article ,[PubDate] = @PubDate WHERE [link] = @link;  
                end  
                else begin  
                     INSERT INTO [ITIronPost] ([Title] ,[link] ,[Content] ,[Article] ,[PubDate]) VALUES (@Title,@link,@Content,@Article,@PubDate) ;  
                end  
            ", posts);  
        tsx.Complete();  
        log.LogInformation($"====文章成功保存到資料庫====");  
    }  
}  
  
private static SqlConnection GetOpenConnection()  
{  
    var conn = new SqlConnection(_connectionString);  
    conn.Open();  
    return conn;  
}  
  
/*上一篇查詢鐵人賽的ITIronManSyncPostService*/  

最後在Azure SQL DataBase使用sql查詢得到結果,可以看到資料正確保存到資料庫。
2018-10-19.23.04.30-image.png


結論

雖然功能跟webjob很類似,BUT,不像是webjob會受限於webapp的狀況,webapp停止運行webjob也會隨之停止。

像是web app service初級版本有運算時間限制,假如超過webapp就會關閉,假如花點小錢升級方案使用always on功能可以避免此情況,但只有基本與更高等級的 App Service 方案才支援,假如專案規格未明確情況下,升級專案可能會浪費資源、金錢。
2018-10-20.19.01.46-image.png

使用TimerTrigger選擇使用情況方案可以避免上述浪費情況,達到使用量=付費金額


上一篇
三十天.NET與Azure漸進式開發專案(13): Azure Function - 來做一個鐵人賽文章清單API
下一篇
三十天.NET與Azure漸進式開發專案(15): Azure做Feed RSS訂閱鐵人賽文章功能
系列文
三十天.NET❤️Azure漸進式開發專案30

尚未有邦友留言

立即登入留言