一、事出有因
1、上周工作原因項目的事情每天都很忙,周五下班和樂師兄下班的時候已經晚上11點了,然后和師兄吃了一個燒烤吃到了12點了(結果啥也沒吃,錢也花了挺多的。ps:程序員建議養生)扯遠了 ,主要是一周比較忙周六沒有進行我們學校的健康報備信息填寫。導致輔導員給我打了6個電話(現在我還是在實習中,所以還歸學校管)自己剛好在看網絡請求這一塊的東西,說干就干!!!
二、知其所以然
1、我們學校的健康報備主要是將自己每天的信息填寫到學校的公眾號上面。打開頁面是這樣的。這個時候我們就要想一下我們是要做什么了。首先我們健康報備的流程是=>打開學校公眾號=>輸入自己的學號點擊查詢=>然后輸入自己的正式情況=>點擊提交。
三、反向分析
1、做為程序員的我們首先要清楚我們要什么,現在我們已經清楚了要做什么了和步驟。現在就是用我們的程序模擬用戶進行正常的報備工作。首先我將報備鏈接從學校公眾號復制出來,然后使用瀏覽器訪問查看我們在進行報備的時候我們向瀏覽器發起了什么和做了什么。
2、在左邊的是我們的頁面,右邊的是網頁請求的文件和信息,我們就一步一步的進行分析。這里我們可以看到我們在訪問頁面的時候會生成一些信息__EVENTVALIDATION 、 __VIEWSTATEGENERATOR 我以前在長沙寫的也是ASPX頁面使用控件程序的時候也會生成一些這個,需要通過這些東西來獲取我們頁面填寫的信息所以這里我們需要保留,因為我們等下需要輸入學號然后點擊查詢,不過不傳這些參數獲取不到我輸入的學號,這個是我嘗試過的哈哈。
3、下面看到的是我輸入了自己的學號點擊查詢獲取到的信息,我們可以看到這里使用的是formData進行傳遞到后台去的,也可以明顯的看到我填寫的信息了。然后進入到了填寫頁面。然后我們在查看頁面上面生成的東西。
4、我們輸入完整的信息之后,點擊報備按鈕又會發生什么呢?可以看到我們提交的formData信息,請求也成功了(今天我已經報備了,所以是這個提示)。現在整個流程我們已經清楚了,以及請求的參數。那就讓我們開始整活吧。
四、開始動手
1、廢話不多說直接創建一個.net core 的項目整活。我先寫了一個簡單的html頁面進行填寫學號信息,然后在寫一個定時任務每天晚上12點之后自動執行,健康報備信息。
public async static Task AsyncQuartz() { await Task.Run(async () => { //創建一個鍵值集合 NameValueCollection nameValue = new NameValueCollection { //定時任務的序列類型是二進制的 { "quartz.serializer.type", "binary" } }; //創建定時任務調度器工廠 StdSchedulerFactory factory = new StdSchedulerFactory(nameValue); //獲取工廠中的調度器 IScheduler scheduler = await factory.GetScheduler(); //開啟調度器 await scheduler.Start(); //然后就是創建我們的任務 //給任務一個身份 //在進行建立 IJobDetail userServiceJob = JobBuilder.Create<HealthForJob>() .WithIdentity("UserServiceJob", "UserServiceJobGroup") .Build(); //任務有了創建觸發器 ITrigger userServiceTrigger = TriggerBuilder.Create() .WithIdentity("userServiceTrigger", "userServiceTriggerGroup") .StartNow() //給定執行時間,然后在重復執行 .WithSimpleSchedule(x => x.WithIntervalInHours(6).RepeatForever()) .Build(); //將任務和觸發器進行綁定放入觸發器中 //單任務調用 await scheduler.ScheduleJob(userServiceJob, userServiceTrigger); }); }
2、首先我們需要模擬用戶向報備網頁發起請求這里我使用的是HttpClient 對象發起請求,怕被攔截我還填了很多請求頭哈哈。但我們發起get請求的時候獲取的是一段長的html字符串。
3、然后我們要使用一個神器進行html分析了。HtmlAgilityPack 它可以解析我們獲取的html字符串代碼
4、我們創建一個HtmlDocument htmlDoc1 = new HtmlDocument(); 對象然后然后將我們獲取的html 對象放到 htmlDoc1.LoadHtml(strHtml);就可以解析成了正常的html了,也可以直接在頁面上面復制xpath結構,然后直接放進來就好了
htmlDoc1.LoadHtml(strHtml); //這里就是通過html結構尋找我們想要的節點信息 var liNodes1 = htmlDoc1.DocumentNode.SelectNodes("//div[@class='aspNetHidden']/input");
5、這里我們獲取到了html節點之后就可以進行正常取數據啦。
6、這里就開始我們的請求三大步了,直接模擬一個form表單請求將我們的數據傳遞就好了
using (HttpContent httpContent = new FormUrlEncodedContent(keyValuePairs)) { httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); strHtml = httpClient.PostAsync("URL", httpContent).Result.Content.ReadAsStringAsync().Result; if (!string.IsNullOrWhiteSpace(strHtml)) { htmlDoc1.LoadHtml(strHtml); var liNodes1 = htmlDoc1.DocumentNode.SelectNodes("//div[@class='aspNetHidden']/input"); keyValuePairs.Clear(); foreach (var item in liNodes1) { var id = item.Attributes["id"].Value; var value = item.Attributes["value"].Value; if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(value)) { keyValuePairs.Add(id, value); } } } }
五、項目部署
1、項目部署使用的是Docker +JenKins 實現自動化部署,現在我在公司也想慢慢推廣因為我們公司服務器權限管的比較嚴格,每次發布測試環境都需要找師兄發布,導致師兄很多時間都在幫我們發布項目。所以這個技術我覺得是很有必要在我們部門推廣。這個項目主要使用的了.net core 3.1 作為框架 Dapper作為數據訪問層,Quartz 定時任務 ,HtmlAgilityPack 進行Html結構分析,Docker 部署項目 ,JenKins 實現項目自動化部署。由於篇幅問題這些技術會在后面的文章分享出來。我自己也多研究一下避免誤人子弟。哈哈
六、個人說明
1、以上就是我寫的全部流程,我們需要重復試錯,因為你要了解寫這個程序的同行的思路哈哈,我還看過一些網站是通過惰性加載信息,還有一些比較重要的信息會通過其他的方式傳遞,就是防止我們爬取,比如京東的商品價格使用Js請求的方式傳遞Jsonp請求,這個這個就需要我們多動手動倒騰了。重點說明一下這個只是自己學習使用的,對於學校健康報備我雙手支持。源碼就不分享了大家動起手來吧。