一個Python小白5個小時爬蟲經歷 【續】

丶Pz發表於2017-02-21

前言

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

 

相關文章