一个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团队。无薪,可学习,哈哈。