Reference:

http://www.shareditor.com/blogshow/?blogId=112

经过半个月的倾力打造,建设好的聊天语料库包含三千多万条简体中文高质量聊天语料,近1G的纯文本数据。此语料库全部基于2万部影视剧字幕,经由爬取、分类、解压、语言识别、编码识别、编码转换、过滤清洗等一系列繁琐过程。把整个建设过程分享出来供大家玩耍。

 

请尊重原创,转载请注明来源网站www.shareditor.com以及原始链接地址

注意:本文提到的程序和脚本都分享在https://github.com/warmheartli/ChatBotCourse。如需直接获取最终语料库,请见文章末尾。

第一步:爬取影视剧字幕

请见我的这篇文章《二十八-脑洞大开:基于美剧字幕的聊天语料库建设方案

第二步:压缩格式分类

下载的字幕有zip格式和rar格式,因为数量比较多,需要做筛选分类,以便后面的处理,这步看似简单实则不易,因为要解决:文件多无法ls的问题、文件名带特殊字符的问题、文件名重名误覆盖问题、扩展名千奇百怪的问题,我写成了python脚本mv_zip.py如下:

import glob
import os
import fnmatch
import shutil
import sys def iterfindfiles(path, fnexp):
for root, dirs, files in os.walk(path):
for filename in fnmatch.filter(files, fnexp):
yield os.path.join(root, filename) i=0
for filename in iterfindfiles(r"./input/", "*.zip"):
i=i+1
newfilename = "zip/" + str(i) + "_" + os.path.basename(filename)
print filename + " <===> " + newfilename
shutil.move(filename, newfilename)

其中的扩展名根据压缩文件可能有的扩展名修改成*.rar、*.RAR、*.zip、*.ZIP等

第三步:解压

解压这一步需要根据所用的操作系统下载不同的解压工具,建议使用unrar和unzip,为了解决解压后文件名可能重名覆盖的问题,我总结出如下两句脚本来实现批量解压:

i=0; for file in `ls`; do mkdir output/${i}; echo "unzip $file -d output/${i}";unzip -P abc $file -d output/${i} > /dev/null; ((i++)); done
i=0; for file in `ls`; do mkdir output/${i}; echo "${i} unrar x $file output/${i}";unrar x $file output/${i} > /dev/null; ((i++)); done

第四步:srt、ass、ssa字幕文件分类整理

当你下载大量字幕并解压后你会发现字幕文件类型有很多种,包括srt、lrc、ass、ssa、sup、idx、str、vtt,但是整体量级上来看srt、ass、ssa占绝对优势,因此简单起见,我们抛弃掉其他格式,只保留这三种,具体分类整理的脚本可以参考第二部压缩格式分类的方法按扩展名整理

第五步:清理目录

在我边整理边分析的过程中发现,我为了避免重名把文件放到不同目录里后,如果再经过一步文件类型整理,会产生非常多的空目录,每次ls都要拉好几屏,所以写了一个自动清理空目录的脚本clear_empty_dir.py,如下:

import glob
import os
import fnmatch
import shutil
import sys def iterfindfiles(path, fnexp):
for root, dirs, files in os.walk(path):
if 0 == len(files) and len(dirs) == 0:
print root
os.rmdir(root) iterfindfiles(r"./input/", "")

第六步:清理非字幕文件

在整个字幕文件分析过程中,总有很多其他文件干扰你的视线,比如txt、html、doc、docx,因为不是我们想要的,因此干脆直接干掉,批量删除脚本del_file.py如下:

import glob
import os
import fnmatch
import shutil
import sys def iterfindfiles(path, fnexp):
for root, dirs, files in os.walk(path):
for filename in fnmatch.filter(files, fnexp):
yield os.path.join(root, filename) for suffix in ("*.mp4", "*.txt", "*.JPG", "*.htm", "*.doc", "*.docx", "*.nfo", "*.sub", "*.idx"):
for filename in iterfindfiles(r"./input/", suffix):
print filename
os.remove(filename)

第七步:多层解压缩

把抓取到的字幕压缩包解压后有的文件里面依然还有压缩包,继续解压才能看到字幕文件,因此上面这些步骤再来一次,不过要做好心理准备,没准需要再来n次!

第八步:舍弃剩余的少量文件

经过以上几步的处理后剩下一批无扩展名的、特殊扩展名如:“srt.简体”,7z等、少量压缩文件,总体不超过50M,想想伟大思想家马克思教导我们要抓主要矛盾,因此这部分我们直接抛弃掉

第九步:编码识别与转码

字幕文件就是这样的没有规范,乃至于各种编码齐聚,什么utf-8、utf-16、gbk、unicode、iso8859琳琅满目应有尽有,我们要统一到一种编码方便使用,索性我们统一到utf-8,get_charset_and_conv.py如下:

import chardet
import sys
import os if __name__ == '__main__':
if len(sys.argv) == 2:
for root, dirs, files in os.walk(sys.argv[1]):
for file in files:
file_path = root + "/" + file
f = open(file_path,'r')
data = f.read()
f.close()
encoding = chardet.detect(data)["encoding"]
if encoding not in ("UTF-8-SIG", "UTF-16LE", "utf-8", "ascii"):
try:
gb_content = data.decode("gb18030")
gb_content.encode('utf-8')
f = open(file_path, 'w')
f.write(gb_content.encode('utf-8'))
f.close()
except:
print "except:", file_path

第十步:筛选中文

考虑到我朝广大人民的爱国热情,我只做中文,所以什么英文、韩文、日文、俄文、火星文、鸟语……全都不要,参考extract_sentence_srt.py如下:

# coding:utf-8
import chardet
import os
import re cn=ur"([\u4e00-\u9fa5]+)"
pattern_cn = re.compile(cn)
jp1=ur"([\u3040-\u309F]+)"
pattern_jp1 = re.compile(jp1)
jp2=ur"([\u30A0-\u30FF]+)"
pattern_jp2 = re.compile(jp2) for root, dirs, files in os.walk("./srt"):
file_count = len(files)
if file_count > 0:
for index, file in enumerate(files):
f = open(root + "/" + file, "r")
content = f.read()
f.close()
encoding = chardet.detect(content)["encoding"]
try:
for sentence in content.decode(encoding).split('\n'):
if len(sentence) > 0:
match_cn = pattern_cn.findall(sentence)
match_jp1 = pattern_jp1.findall(sentence)
match_jp2 = pattern_jp2.findall(sentence)
sentence = sentence.strip()
if len(match_cn)>0 and len(match_jp1)==0 and len(match_jp2) == 0 and len(sentence)>1 and len(sentence.split(' ')) < 10:
print sentence.encode('utf-8')
except:
continue

请尊重原创,转载请注明来源网站www.shareditor.com以及原始链接地址

第十一步:字幕中的句子提取

不同格式的字幕有特定的格式,除了句子之外还有很多字幕的控制语句,我们一律过滤掉,只提取我们想要的重点内容,因为不同的格式都不一样,在这里不一一举例了,感兴趣可以去我的github查看,在这里单独列出ssa格式字幕的部分代码供参考:

if line.find('Dialogue') == 0 and len(line) < 500:
fields = line.split(',')
sentence = fields[len(fields)-1]
tag_fields = sentence.split('}')
if len(tag_fields) > 1:
sentence = tag_fields[len(tag_fields)-1]

第十二步:内容过滤

经过上面几步的处理,其实已经形成了完整的语料库了,只是里面还有一些不像聊天的内容我们需要进一步做优化,包括:过滤特殊的unicode字符、过滤特殊的关键词(如:字幕、时间轴、校对……)、去除字幕样式标签、去除html标签、去除连续特殊字符、去除转义字符、去除剧集信息等,具体代码如下:

# coding:utf-8
import sys
import re
import chardet if __name__ == '__main__':
#illegal=ur"([\u2000-\u2010]+)"
illegal=ur"([\u0000-\u2010]+)"
pattern_illegals = [re.compile(ur"([\u2000-\u2010]+)"), re.compile(ur"([\u0090-\u0099]+)")]
filters = ["字幕", "时间轴:", "校对:", "翻译:", "后期:", "监制:"]
filters.append("时间轴:")
filters.append("校对:")
filters.append("翻译:")
filters.append("后期:")
filters.append("监制:")
filters.append("禁止用作任何商业盈利行为")
filters.append("http")
htmltagregex = re.compile(r'<[^>]+>',re.S)
brace_regex = re.compile(r'\{.*\}',re.S)
slash_regex = re.compile(r'\\\w',re.S)
repeat_regex = re.compile(r'[-=]{10}',re.S)
f = open("./corpus/all.out", "r")
count=0
while True:
line = f.readline()
if line:
line = line.strip() # 编码识别,不是utf-8就过滤
gb_content = ''
try:
gb_content = line.decode("utf-8")
except Exception as e:
sys.stderr.write("decode error: ", line)
continue # 中文识别,不是中文就过滤
need_continue = False
for pattern_illegal in pattern_illegals:
match_illegal = pattern_illegal.findall(gb_content)
if len(match_illegal) > 0:
sys.stderr.write("match_illegal error: %s\n" % line)
need_continue = True
break
if need_continue:
continue # 关键词过滤
need_continue = False
for filter in filters:
try:
line.index(filter)
sys.stderr.write("filter keyword of %s %s\n" % (filter, line))
need_continue = True
break
except:
pass
if need_continue:
continue # 去掉剧集信息
if re.match('.*第.*季.*', line):
sys.stderr.write("filter copora %s\n" % line)
continue
if re.match('.*第.*集.*', line):
sys.stderr.write("filter copora %s\n" % line)
continue
if re.match('.*第.*帧.*', line):
sys.stderr.write("filter copora %s\n" % line)
continue # 去html标签
line = htmltagregex.sub('',line) # 去花括号修饰
line = brace_regex.sub('', line) # 去转义
line = slash_regex.sub('', line) # 去重复
new_line = repeat_regex.sub('', line)
if len(new_line) != len(line):
continue # 去特殊字符
line = line.replace('-', '').strip() if len(line) > 0:
sys.stdout.write("%s\n" % line)
count+=1
else:
break
f.close()
pass

自己动手做聊天机器人 二十九-重磅:近1GB的三千万聊天语料供出的更多相关文章

  1. FreeSql (二十九)Lambda 表达式

    FreeSql 支持功能丰富的表达式函数解析,方便程序员在不了解数据库函数的情况下编写代码.这是 FreeSql 非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基本都可以使用对应的表达 ...

  2. JAVA之旅(二十九)——文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习

    JAVA之旅(二十九)--文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习 我们继续学习File 一.文件递归 我们可以来实现 ...

  3. Bootstrap <基础二十九>面板(Panels)

    Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素添加 class .panel 和 class .pa ...

  4. Web 开发人员和设计师必读文章推荐【系列二十九】

    <Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  5. 一步一步来做WebQQ机器人-(二)(第一次登陆)

    // 预计会有这些步骤,当然某些步骤可能会合并: 验证码 第一次登陆 第二次登陆 保持在线和接收消息 获取好友和群列表 发送消息 变成智能的(*゚∀゚*) webqq的登陆,分为2步,本文主要讲第一次 ...

  6. WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

    原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...

  7. VMwarevSphere 服务器虚拟化之二十九 桌面虚拟化之安装View副本服务器

    VMwarevSphere 服务器虚拟化之二十九  桌面虚拟化之安装View副本服务器 VMware View中高可用性可是一个必须要考虑的问题.在整个虚拟桌面环境中View Connection S ...

  8. Bootstrap入门(二十九)JS插件6:弹出框

    Bootstrap入门(二十九)JS插件6:弹出框 加入小覆盖的内容,像在iPad上,用于存放非主要信息 弹出框是依赖于工具提示插件的,那它也和工具提示是一样的,是需要初始化才能够使用的 首先我们引入 ...

  9. mysql进阶(二十九)常用函数

    mysql进阶(二十九)常用函数 一.数学函数 ABS(x) 返回x的绝对值 BIN(x) 返回x的二进制(OCT返回八进制,HEX返回十六进制) CEILING(x) 返回大于x的最小整数值 EXP ...

随机推荐

  1. Windows下MongoDB安装及创建用户名和密码

    下载MongoDB的安装文件https://www.mongodb.com/download-center#community,选择合适的版本(注:本人选择的是3.2.6) 下载完MongoDB.ms ...

  2. Review Board的使用

    代码审核工具.先在命令行界面,进入到工程的Main目录下,然后使用命令 svn diff>yus.diff  这样就将Main里面的所有内容生成了,然后在浏览器里进入到自己的Review Boa ...

  3. STL笔记之【map之添加元素】

    //---------------------------------------------------------// 向map中插入元素的方法比较//---------------------- ...

  4. usb调试

    修改文件:/home/mxy/code/v1/kernel-3.10/drivers/power/mediatek/battery_common.c //bool AutoDebug=true;//x ...

  5. zf-关于平台的用户名密码的设置

    比如说安徽桐城的用户名密码在哪张表里设置 桐城市人民统一电子政务平台是http://localhost:8088/tc/ptzwfw.action 这个链接 在zwfw_tc 数据库的 PT_LOGI ...

  6. 把自己的电脑做服务器发布tomcat的项目外网访问

    1.首先你要确定你有一个外网ip地址.如果你分配到的是一个局域网IP地址需要经过一系列的转换为外网ip地址,然后继续下面操作. 2.拿到外网IP地址,进行tomcat的server.xml文件的配置. ...

  7. 谈谈java的BlockingQueue

    http://www.cnblogs.com/archy_yu/archive/2013/04/19/3018479.html 博客园 首页 新随笔 联系 管理 随笔- 92  文章- 0  评论- ...

  8. zookeeper常用sehll命令

    ZooKeeper服务命令: 在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作 1. 启动ZK服务:       sh bin/zkServer.sh start ...

  9. android4.0 的图库Gallery2代码分析(一)

    最近迫于生存压力,不得不给人兼职打工.故在博文中加了个求点击的链接.麻烦有时间的博友们帮我点击一下.没时间的不用勉强啊.不过请放心,我是做技术的,肯定链接没病毒,就是我打工的淘宝店铺.嘻嘻.http: ...

  10. [算法] aov图拓扑算法

    #include <stdio.h> #include <string.h> #include <stdlib.h> #include <queue> ...