前篇文章版本有個缺點:每一次網頁運行會重新抓取一次網頁內容
,假如做成固定時間爬取一次網頁,接著把資料存到資料庫,這樣才可以避免重複行為的浪費
。
要達到目的,可以利用 Timer Trigger 做一個輕量級排程器,把整理後的資料保存到前面介紹的 Azure SQL Database ,方便之後使用SQL篩選查詢資料。
新增/現有Azure Function > 函式 > 點擊 Timer Trigger 圖案 > 填寫名稱、排程時間 > 建立
建立預設自帶一個Log小程式,可以點擊執行
做線上測試。
運行週期可以在function.json - schedule欄位
做修改,使用CRON指定時間區間,不熟悉的讀者可以到線上工具Online Cron了解,舉例0 * * 1/1 * ? *
代表每小時跑一次
在線上開發雖然輕便、方便,但是也造成開發的麻煩,像是提示系統、檔案管理、動作緩慢問題。
這時候我們可以使用Azure Function提供下載線上專案的功能,轉成VS方案在自己的電腦打開編輯。
方式點選Function > 概觀 > 下載應用程式內容 > 選擇下載內容與Visual Studio專案
這邊記得要勾選包含應用程式設定,否則本機環境無法運行,如圖片
下載完解壓縮,可以看到熟悉的.csproj專案檔
,我們只需要
專案結構跟線上結構一樣。
可以在本機運行、測試 TimerTrigger 真是方便又酷炫!
【第一步】藉由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
【第二步】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查詢得到結果,可以看到資料正確保存到資料庫。
雖然功能跟webjob很類似,BUT,不像是webjob會受限於webapp的狀況
,webapp停止運行webjob也會隨之停止。
像是web app service初級版本有運算時間限制,假如超過webapp就會關閉,假如花點小錢升級方案使用always on
功能可以避免此情況,但只有基本與更高等級的 App Service 方案才支援,假如專案規格未明確情況下,升級專案可能會浪費資源、金錢。
使用TimerTrigger選擇使用情況方案可以避免上述浪費情況,達到使用量=付費金額
。