引言:

我写博客的习惯基本上都是:

使用 Typora 或者 haroopad 这样支持 Markdown 语法的实时可视化编辑器先编写好,然后再发布到 CSDN 或者我自己的 hexo 博客地址上。

不在在线编辑器上编写的原因是可以博客本地备份而且内容不容易丢失。所以,此时假设我们写完了一篇博客,即有一个 .md 的文件,要如何将其自动录入到数据库中?多个 .md 文件如何一次录入?

设计思路:

用过 hexo 静态博客框架的应该都知道,假如我们想要发布一篇博客,我们需要在 source/_posts 目录下放入编写的好的 .md 文件,然后通过 hexo generate 指令来为个 .md 格式的博客文件 生成对应的 .html 静态页面文件,参考这个思路,数据源同样是 .md 文件,区别只在于生成静态页面或者是录入数据库而已。

1.文件批处理:

之前我写过一篇关于使用 Python 如何编写一个自动批量处理文件的工具 【Python 编写自动化工具】,那个工具完成了批量获取文件属性和内容的操作,唯一需要做的就是如何将获取的数据插入数据库中,这里我使用的数据库是 MongoDB 。

2.操作数据库:

使用 Python 语言操作数据库,碰巧我之前也写过一篇爬虫数据存入 MongoDB 数据库的博客 【Python 爬虫7——自定义Item Pipeline将数据存入MongoDB】,原理其实很简单,就是借助 pymongo 这个插件工具来操作 MongoDB 数据库。

假如已经安装了 mongoengine 则无需再安装 pymongo ,因为已经默认一起安装了,否则需要单独安装 pymongo 。

3.数据结构:

关于最后数据已什么样的数据结构体存入数据库中,这取决于应用环境的需求,这里我的存入结构大致如下:

  • .md 文件的名称坐标博客标题;
  • 文件创建时间作为发布时间;
  • 文件所在目录为文件分类;
  • 文件内容直接写入博客内容字段,例如 content

源码实现:

1.遍历文件:

首先,编写需要用到的批量遍历文件和获取属性的方法:

#!/usr/bin/env python
# -*- coding: utf-8 -*-import os.path,time
from pymongo import MongoClient# 获取指定目录指定后缀名的文件列表
def getFileList(path,endStr):'''获取指定目录下,指定后缀的文件列表'''r_list = []f_list = os.listdir(path)   #获取目录列表for i in f_list:# 分离文件名和后缀名,过滤掉工具脚本file_endStr = os.path.splitext(i)[1]# 判断是否是目录if file_endStr == '':#=================〉这一行很必要(补全完整目录)i = os.path.join(path, i)if os.path.isdir(i):f_list1 = os.listdir(path+'/'+i)for j in f_list1:# 过滤出指定后缀 endStr 后缀的文件if os.path.splitext(j)[1] == endStr:# 为了清晰目录把文件所在目录也标识出来r_list.append(i+'/'+j)# print j.decode("string_escape")elif file_endStr == endStr:r_list.append(i)return r_list# 获取文件创建时间
def get_FileCreateTime(filePath):t = os.path.getctime(filePath)return TimeStampToTime(t)# 把时间戳转化为时间: 1479264792 to 2016-11-16 10:53:12'''
def TimeStampToTime(timestamp):timeStruct = time.localtime(timestamp)return time.strftime('%Y-%m-%d %H:%M:%S',timeStruct)# 获取目录中去掉前面路径和后缀的文件名字
def getFileSimpleName(filePath):name = ''# 先去掉后缀name = os.path.splitext(filePath)[0]# 获取最后一个斜杠位置index = name.rfind('/')# 找不到则返回 -1if index != -1:name = name[index+1:] # 截取斜杠后面到结尾内容# print namereturn name# 获得分类文件目录名称def getTypeNameByPath(filePath):fileTag = ''# 获取最后一个斜杠位置index = filePath.rfind('/')# 找不到则返回 -1if index != -1:# 截取斜杠后面到结尾内容fileTag = filePath[:index]# 截掉前面部分index = fileTag.rfind('/')if index != -1:fileTag = fileTag[index+1:]# print fileTagreturn fileTag# 获取文件内容
def getArticleContent(filePath):file = open(filePath,"r")content = file.read()file.close()return content

然后调用这些方法获取需要的属性:

# 指定目录
path = './blogs/'
print(u'文件目录:'+path)
# 得到文件列表
files = getFileList(path,'.md')
print files
for i in files:print 'title: '+getFileSimpleName((i.decode("string_escape")))print 'date: '+get_FileCreateTime((i.decode("string_escape")))print 'tags: ['+getTypeNameByPath((i.decode("string_escape")))+']'

2.数据库操作方法:

创建一个数据库的操作类,写完初始化函数后,先写一个数据库初始化函数来连接数据保存的数据库,然后编写一个插入数据的方法,这里需要通过 collection.find 接口判断数据库中是否已存在相同的数据:

  • 假如存在,则通过 collection.update 方法更新部分项的数据;
  • 假如不存在,直接用 collection.insert 方法将数据插入数据库中。

最终数据库操作类的内容如下:

class MongoDBHelper(object):def __init__(self):self.InitMongoDBConnect()# 初始化 MongoDB 的连接def InitMongoDBConnect(self):# 数据库 ip 地址和端口号connection = MongoClient('localhost',27017)  # db_namedb = connection['local']# document_nameself.collection = db['articles']def CheckData(self,title):# 查询是否存在相同的数据datas = self.collection.find({'title':title})# print datas.count()if datas.count() > 0:return True,datas[0]else:return False,0def SaveData(self,data):if data != {}:exits,dat = self.CheckData(data['title'])if exits == True:# 更新文本内容self.collection.update({'_id':dat['_id']},{'$set':{'content':data['content']}})print data['title'].decode("utf8",'ignore')+u'-->数据已更新!!'else:self.collection.insert(data)print data['title'].decode("utf8",'ignore')+u'-->数据已存入'

3.数据写入:

通过调用文件操作方法,遍历获取文件目录列表,然后使用循环体去分别获取每个文件的属性,循环之前先创建一个数据库操作对象,每个文件数据都通过数据库操作对象写入到数据库中:

# 指定目录
path = './blogs/'
helper = MongoDBHelper()
print(u'文件目录:'+path)
# 得到文件列表
files = getFileList(path,'.md')
data = {}
for i in files:# 平台判断if sys.platform == 'win32':title = getFileSimpleName(i.decode("gbk",'ignore'))date = get_FileCreateTime(i.decode("gbk",'ignore'))tags = getTypeNameByPath(i.decode("gbk",'ignore'))content = getArticleContent(i.decode("gbk",'ignore'))title = title.encode('utf-8')date = date.encode('utf-8')tags = tags.encode('utf-8')content = content.encode('utf-8')#print title.decode("utf8",'ignore')else:title = getFileSimpleName(i)date = get_FileCreateTime(i)tags = getTypeNameByPath(i)content = getArticleContent(i)#print titledata = {'title':title,'date':date,'tags':tags,'content':content}# 文件数据写入数据库helper.SaveData(data)

4.执行结果:

在命令行中运行编写好的工具脚本(记得需要提前让 MongoDB 处于运行状态),输入如下:

E:\Python Projects\Django\hBlog\source>python SaveToMongoDB.py
文件目录:./blogs/
CentOS 7.0最小安装及配置-->数据已存入
CentOS 7常用工具安装-->数据已存入
Lua 5.3 元表和元方法-->数据已存入
lua 5.3 核心源码解读-->数据已存入
Lua 5.3 源码解读(一) VS 2015 编译源码-->数据已存入
Lua 5.3 源码解读(二) 断点调试-->数据已存入
lua 常用操作-->数据已存入

通过可视化工具查看数据库内容,可以看到数据已经成功写入到数据库中:

为了避免未启动 MongoDB 的服务就执行对数据库的操作,可以在工具中写入一个启动数据库服务的功能:

# 指定目录
path = './blogs/'# windows 平台启动数据库服务
if sys.platform == 'win32':os.system("net start MongoService") helper = MongoDBHelper()

执行结果如下:

E:\Python Projects\Django\hBlog\source>python SaveToMongoDB.py
MongoDB3.4.7 服务正在启动 ..
MongoDB3.4.7 服务已经启动成功。文件目录:./blogs/
CentOS 7.0最小安装及配置-->数据已更新!!
CentOS 7常用工具安装-->数据已更新!!
Lua 5.3 元表和元方法-->数据已更新!!
lua 5.3 核心源码解读-->数据已更新!!
Lua 5.3 源码解读(一) VS 2015 编译源码-->数据已更新!!
Lua 5.3 源码解读(二) 断点调试-->数据已更新!!
lua 常用操作-->数据已更新!!

常见问题:

由于文章标题是中文的,因为在 Python 中字符串默认使用 ascii 编码,而数据库中字符串需要使用 utf-8 ,两者产生了冲突, 所以在将数据插入 MongoDB 数据库的时候出现了如下错误:

bson.errors.InvalidStringData: strings in documents must be valid UTF-8: 'CentOS7.0\xd7\xee\xd0\xa1\xb0\xb2\xd7\xb0\xbc\xb0\xc5\xe4\xd6\xc3'

当然对使用非 'utf8' 方式编码的字符串直接使用 datastring.decode('utf8') 还会触发如下报错:

UnicodeDecodeError: 'utf8' codec can't decode byte 0xd7 in position 10: invalid
continuation byte

解决上述问题其实很简单,但是 Linux 平台下和 Windows 平台下略有差别,所以处理也需要通过 sys.platform 接口进行平台判断:

import sys
if sys.platform == 'win32':...
else:...
  • Linux 平台:

    在脚本的开头位置设置默认的编码方式即可,有两种方式:

    • 方式一:

      
      # -- coding: utf-8 --
      

    • 方式二:

      import sys# 设置字符串使用 utf8 编码方式reload(sys)
      sys.setdefaultencoding('utf8')

    Linux 下无需对字符进行额外的操作就能顺利存入数据库中。

  • Windows 平台:

    Windows 平台即便设置了 # -*- coding: utf-8 -*- 好像也还是无法解决字符串编码的问题,所以需要在代码中对字符串做修改:

    title = getFileSimpleName((i.decode("gbk",'ignore')))
    print title
    title = title.encode('utf-8')
    print title

    即先通过 decode("gbk",'ignore') 解码原本的字符串数据,再通过 encode('utf-8') 将数据编码为可以存入数据库中的 'utf8' 编码格式,然后再存入数据库就没问题了。

更多跟编码相关的知识可以查看这篇博客:Python编码UNICODE GBK UTF-8字符集转换的正确姿势 ,里面提供了一个函数库:

# win下命令行参数为gbk编码:star.gbk2unicode(sys.argv[1]) + u'也有'
def gbk2unicode(s):return s.decode('gbk', 'ignore')# 脚本文件#coding:utf-8时默认不带u的字符串为utf8字符串:star.utf82unicode('我')
def utf82unicode(s):return s.decode('utf-8', 'ignore')# 带u的字符串为unicode
# star.unicode2gbk(u'\u4e5f\u6709')
# star.unicode2gbk(u'也有')
def unicode2gbk(s):return s.encode('gbk')# 带u的字符串为unicode
# star.unicode2utf8(u'\u4e5f\u6709')
# star.unicode2utf8(u'也有')
def unicode2utf8(s):return s.encode('utf-8')# win下命令行参数为gbk编码:star.gbk2utf8(sys.argv[1]) + '也有'
def gbk2utf8(s):return s.decode('gbk', 'ignore').encode('utf-8')def utf82gbk(s):return s.decode('utf-8', 'ignore').encode('gbk')

参考资料:

  • python操作数据库之批量导入
  • 【代码片-1】 python 批量导入MongoDB数据库
  • 一个python批量给mongodb添加数据例子
  • Python 多线程读取文本文件,写入Mongodb
  • MongoDB中ObjectId生成规则参考
  • 解决UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe5 in position 108: ordinal not in range(128

Python 文件数据批量录入数据库(MongoDB)相关推荐

  1. java excel批量导入数据库数据_Java实现Excel数据批量导入数据库

    Java实现Excel数据批量导入数据库 概述: 这个小工具类是工作中的一个小插曲哦,因为提数的时候需要跨数据库导数... 有的是需要从oracle导入mysql ,有的是从mysql导入oracle ...

  2. c语言学习进阶-C语言带命令行参数的文件数据批量计算

    C语言带命令行参数的文件数据批量计算 (1)假设输入文件中的数据为多行整数,把数据文件命名为"InputData.txt",也可以命名为任意的文件名,尝试设计一个c 语言程序, 主 ...

  3. 大量数据批量插入数据库

    大量数据批量插入数据库 前言 工作时遇到了大量数据需要插入到数据库的情况,一条条的插入速度慢效率低下,不能满足需求,为了解决此问题采用了sql中使用foreach,并在service中设置批量来进行批 ...

  4. [Excel知识技能] Txt文件数据批量导入Excel

    记录(日期: 2022/5/20) 在实际工作中,遇到过将Txt格式的数据导入到Excel中,为此特意记录以下操作过程,便于日后的回顾和学习 需要导入的文本文件如下图所示: Txt文本数据源 Site ...

  5. 分布式任务-数据批量新增数据库

    分布式-数据批量新增数据库 0.pojo package com.mall.order.pojo; import org.apache.commons.lang3.builder.ToStringBu ...

  6. DataTable数据批量写入数据库三种方法比较

    DataTable数据批量写入数据库三种方法比较 标签: it 分类: C# 1)   insert循环插入: 2)   sqldataadapter.update(dataset,tablename ...

  7. Python批量Excel文件数据导入SQLite数据库的优化方案

    说明:1)需要安装扩展库openpyxl:2)随着数据库的增大,导入速度可能会有所下降:3)本文只考虑Python代码优化,没有涉及数据库的优化:4)本文要点在于使用executemany实现批量数据 ...

  8. python读取excel文件数据写入MySQL数据库(入门级)

    写入前准备 1.window电脑提前安装好MySQL 2.知道自己MySQL的密码和用户名 3.提前建好要写入的数据库和数据表 1.首先测试写入一条数据进去MySQL在尝试批量写入 1.1第一数据类型 ...

  9. 使用python将数据存入SQLite3数据库

    Python从网站上抓取的数据为了可以重复利用,一般都会存储下来,存储方式最简单的会选择存储到文本文件,常见的有方式TXT.CSV.EXCEL等,还有一种方式是将数据存储到数据库,这样也方便管理,常见 ...

最新文章

  1. 尚硅谷Java视频教程导航(学习路线图)
  2. 细思极恐!只需54块钱,你也能让AI伪造一系列联合国发言
  3. node.js 调试 eggs launch.json配置信息
  4. 将String转换成Int数组-Java
  5. WebService生成客户端代理的工具WSDL参数介绍
  6. python最大公约数计算_使用Python求解最大公约数的实现方法
  7. 2017ACM/ICPC广西邀请赛题解
  8. Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: org/dom4j/io/SAXReader
  9. 倾听开源Android的另类声音
  10. KETTLE相关问题处理
  11. 安卓火狐浏览器wifi远程调试没有扫描二维码应用的问题
  12. 18个Java开源CMS系统一览
  13. Docker配置consol
  14. vue 实现元素可拖曳
  15. 窗口函数_LAG()与LEAD() 详解
  16. 【Redis详细安装教程】
  17. 吉首大学第九届"新星杯"大学生程序设计大赛 C.始战
  18. 学生用ChatGPT拿下全班最高分!教授惊呆!全美高校打响AI反击战...
  19. 关于校园新闻系统设计的答辩流程指导
  20. 使用AFS, Active Directory和SSSD搭建用于集成电路设计的分布式存储系统 【一】

热门文章

  1. pdf怎么转换成txt?这些方法快收藏起来
  2. OJ每日一练——买房子
  3. DNS—domain name server域名服务器
  4. 错误整理二 | assertThat, equalTo, @RunWith, @SpringBootTest标红
  5. 【附上解释】爬取A股所有上市公司的信息并存储到数据库或者是csv文件中
  6. 首届“中国物联网数据基础设施最佳案例评选”结果出炉
  7. 硬盘安装到计算机里面读不出来的,新买的硬盘怎么使用?安装到电脑上系统里不显示怎么办?...
  8. codecombat计算机科学2,网易极客战记(CodeCombat) 2021 官方免费版
  9. 用拉普拉斯变换求零状态响应_拉普拉斯算子的FPGA实现方法
  10. 基于Android studio的个人日程时间管理系统java