因為我最近忙、所以我寫了它
一、事出有因
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請求,這個這個就需要我們多動手動倒騰了。重點說明一下這個只是自己學習使用的,對於學校健康報備我雙手支援。原始碼就不分享了大家動起手來吧。