一个Python小白5个小时爬虫经历 【续】

前言

  昨天实现了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团队。无薪,可学习,哈哈。

 

posted @ 2017-02-21 17:46  丶Pz  阅读(3680)  评论(4编辑  收藏  举报