前言
昨天實現了python簡單的資料採集之後本來還挺高興的,結果發現在.NET讀取txt檔案後反序列化總是報錯。具體錯誤原因好像是從txt讀取資料之後會自動加一個隱藏的字串,沒錯,肉眼看不見,就導致不是合法的json格式,最終失敗。不說了,反序列化浪費了我大量的時間,下面進入正題。
程式碼重構
問題就出來儲存上,所以儲存的檔案我首先把 .txt 換成 .json 檔案,後來在仔細看生成的文件,發現少了中括號[]和每條資料之間的逗號。於是乎,修改後的程式碼如下。
import match import os import datetime import json def writeToTxt(list_name,file_path): try: #這裡直接write item 即可,不要自己給序列化在寫入,會導致json格式不正確的問題 fp = open(file_path,"w+",encoding='utf-8') l = len(list_name) i = 0 #新增左中括號 fp.write('[') for item in list_name: #直接將專案write到 json檔案中 fp.write(item) #新增每一項之間的逗號 if i<l-1: fp.write(',\n') i += 1 fp.write(']') #新增右中括號 fp.close() except IOError: print("fail to open file") #def getStr(item): #之前用這段程式碼處理item,後來發現,不用處理,直接儲存反而更好,自己處理了,會導致部落格中亂七八糟的字元影響反序列化 # return str(item).replace('\'','\"')+',\n' def saveBlogs(): for i in range(1,2): print('request for '+str(i)+'...') blogs = match.blogParser(i,10) #儲存到檔案 path = createFile() writeToTxt(blogs,path+'/blog_'+ str(i) +'.json') print('第'+ str(i) +'頁已經完成') return 'success' def createFile(): date = datetime.datetime.now().strftime('%Y-%m-%d') path = '/'+date if os.path.exists(path): return path else: os.mkdir(path) return path result = saveBlogs() print(result)
最終生成了完美的json。下圖只貼上其中一項,當然是我昨天發的那篇啦。PS 前篇地址:http://www.cnblogs.com/panzi/p/6421826.html
轉戰.NET CORE
終於把資料格式搞定了。下面就是到資料的事情了,很簡單,不過在寫程式碼過程中順便看了一下 .NET Core的檔案系統[3]:由PhysicalFileProvider構建的物理檔案系統 。然後進行實戰。首先,json都存放在在檔案中,肯定要遍歷檔案了。
從那篇部落格中copy部分程式碼,來實現檔案系統的訪問和解析。
定義IFileManager 介面
public interface IFileManager { /// <summary> /// 讀取檔案,獲取檔案內容 /// </summary> /// <param name="fileHandler"></param> void HandleFile(Action<string> fileHandler); }
然後實現介面內容,主要呢,第一,遍歷資料夾得到檔案,然後輸出相應的檔案內容。第二,反序列化文字內容轉成實體。第三,加入到Elastisearch中。
public IFileProvider FileProvider { get; private set; } public FileManager(IFileProvider fileProvider) { this.FileProvider = fileProvider; } public void HandleFile(Action<string> fileHandler) { //通過FileProvider讀取檔案,遍歷 foreach (var fileInfo in this.FileProvider.GetDirectoryContents("")) { //讀取檔案內容(json) string result = ReadAllTextAsync(fileInfo.Name).Result; //執行處理 fileHandler(result); } }
以上為FileManger部分程式碼。
然後反序列化得到的文字內容。
//遍歷已經蒐集好的json文件 manager.HandleFile(json => { //反序列化得到實體 var entities = serializer.JsonToEntities<DotNetLive.Search.Entities.CnBlogs.Blog>(json); //批量新增到ES中 int result = search.IndexMany(entities); Console.WriteLine("加入" + result + "資料"); });
當然,程式啟動的時候要註冊相應的服務。
public static IServiceProvider RegisterServices() { string folder = DateTime.Now.ToString("yyyy-MM-dd"); var service = new ServiceCollection() //定位到資料夾,當前日期 .AddSingleton<IFileProvider>(new PhysicalFileProvider($@"D:\{folder}")) .AddSingleton<IFileManager, FileManager>() //序列化器 .AddSingleton<ISerializer,CnBlogsSerializer>() .BuildServiceProvider(); return service; }
執行結果
至於為什麼是180條,因為我在python獲取介面的時候寫的是 for in range(1,10),每次請求介面返回20條,請求了9次,然後合併成一個json檔案儲存。
好的,最後在看一下ES中的資料:
總結
紙上得來終覺淺,絕知此事要躬行。這句話一點沒錯,看和做真是兩碼事。不過還好,資料採集階段就告一段落了。不扯了,跑程式去了。小夥伴們下期再見。
github程式碼參見:https://github.com/dotnetlive/dotnetlive.search/tree/master/src/Tools/cnblogs PS:有興趣的小夥伴可以加入dotnetlive團隊。無薪,可學習,哈哈。