前言
昨天實現了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團隊。無薪,可學習,哈哈。