Python 如何将扫描文本中的数据导入Django模型
我有数百页的“测验”题、多项选择题和相关的答案和解释。我正在尝试创建一个简单的Django应用程序来管理这些问题。我创建了一个简单但有效的Python解析器,将扫描的OCR页面解析为适当的对象 我希望有一个“实用工具”,使这个Django应用程序的管理员能够将OCR论文中的测验内容导入到相关的Django DB表中。这将是一项罕见的任务,而且不一定适合包含在web UI中 我曾询问过如何使用中间JSON/YAML fixture,并被告知更合适的方法是直接创建和保存模型的实例[1]。然后,我尝试按照[2]和[3]建议的思路创建一个独立脚本,但无法克服这个问题Python 如何将扫描文本中的数据导入Django模型,python,django,import,Python,Django,Import,我有数百页的“测验”题、多项选择题和相关的答案和解释。我正在尝试创建一个简单的Django应用程序来管理这些问题。我创建了一个简单但有效的Python解析器,将扫描的OCR页面解析为适当的对象 我希望有一个“实用工具”,使这个Django应用程序的管理员能够将OCR论文中的测验内容导入到相关的Django DB表中。这将是一项罕见的任务,而且不一定适合包含在web UI中 我曾询问过如何使用中间JSON/YAML fixture,并被告知更合适的方法是直接创建和保存模型的实例[1]。然后,我尝试
kwargs={“应用程序标签”:模型模块。\名称\拆分('.')[-2]}
索引器:列表索引超出范围
错误
我还遇到了[4]关于创建自定义django-admin.py/manage.py命令的内容。这似乎是一种逻辑上恰当的处理任务的方法;但是,我很想听听那些更有经验和头脑的人的意见(我已经把我的都吃光了:)
参考资料:
示例:
- 光学字符识别文本
- Django模型
class Question(models.Model): text = models.TextField() class Choice(models.Model): question = models.ForeignKey(Question) order = models.IntegerField(default=1) text = models.TextField()
- 目标,像这样的
q = Question.objects.create(text="Hiedegger is a _____ .") q.save() c = Choice(text="philosopher", order=1, question=q.pk) c.save()
- 这是我提出的工作版本。肮脏,但有效。@akonsu和@Ivan Kharlamov都很有帮助。谢谢
import os, re, Levenshtein as lev, codecs
from SimpleQuiz.quiz.models import Choice, Question
from django.core.management.base import BaseCommand, CommandError
import optparse
class Command(BaseCommand):
args = '--datapath=/path/to/text/data/'
can_import_settings = True
help = 'Imports scanned text into Questions and Choices'
option_list = BaseCommand.option_list + (
optparse.make_option('--datapath', action='store', type='string',
dest='datapath',
help='Path to OCRd text files to be parsed.'),
)
requires_model_validation = True
# Parser REs
BACKUP_RE = re.compile(r'\~$|bak$|back$|backup$')
QUEST_RE = re.compile(r'^[0-9]{1,3}[.][ ]')
CHOICE_RE = re.compile(r'^[a-e][.][ ]')
def handle(self, *args, **options):
# get the data path
try:
os.path.exists(options['datapath'])
except Exception as e:
raise CommandError("None or invalid path provided: %s" % e.message)
self.datapath = os.path.expanduser(options['datapath'])
# generate list of text strings from lines in target files
self.data_lines = []
for fn in os.listdir(os.path.join(self.datapath, 'questions/')):
if self.BACKUP_RE.search(fn):
self.stderr.write("Skipping backup: %s\n" % (fn))
else:
for line in codecs.open(os.path.join(self.datapath, 'questions/', fn), 'r', encoding='latin-1'):
if not self.is_boilerplate(line):
if not line.strip() == '':
self.data_lines.append(line)
#-----------------------------------------------------------------------
#--------------------- Parse the text lines and create Questions/Choices
#-----------------------------------------------------------------------
cur_quest = None
cur_choice = None
cur_is_quest = False
questions = {}
choices = {}
for line in self.data_lines:
if self.is_question(line):
[n, txt] = line.split('.', 1)
qtext = txt.rstrip() + " "
q = Question.objects.create(text=qtext)
q.save()
cur_quest = q.pk
questions[cur_quest] = q
cur_is_quest = True
elif self.is_choice(line):
[n, txt] = line.split('.', 1)
num = self.char2dig(n)
ctext = txt.rstrip() + " "
c = Choice.objects.create(text=ctext, order=num, question=questions[cur_quest])
c.save()
cur_choice = c.pk
choices[cur_choice] = c
cur_is_quest = False
else:
if cur_is_quest:
questions[cur_quest].text += line.rstrip() + " "
questions[cur_quest].save()
else:
choices[cur_choice].text += line.rstrip() + " "
choices[cur_choice].save()
self.stdout.write("----- FINISHED -----\n")
return None
def is_question(self, arg_str):
if self.QUEST_RE.search(arg_str):
return True
else:
return False
def is_choice(self, arg_str):
if self.CHOICE_RE.search(arg_str):
return True
else:
return False
def char2dig(self, x):
if x == 'a':
return 1
if x == 'b':
return 2
if x == 'c':
return 3
if x == 'd':
return 4
if x == 'e':
return 5
def is_boilerplate(self, arg_str):
boilerplate = [u'MFT PRACTICE EXAMINATIONS',
u'BERKELEY TRAINING ASSOCIATES ' + u'\u00A9' + u' 2009',
u'BERKELEY TRAINING ASSOCIATES',
u'MARRIAGE AND FAMILY THERAPY',
u'PRACTICE EXAMINATION 41',
u'Page 0', u'Page 1', u'Page 2', u'Page 3', u'Page 4',
u'Page 5', u'Page 6', u'Page 7', u'Page 8', u'Page 9',
]
for bp in boilerplate:
if lev.distance(bp.encode('utf-8'), arg_str.encode('utf-8')) < 4:
return True
return False
导入操作系统、re、Levenshtein作为lev、编解码器
从SimpleQuiz.quick.models导入选择,问题
从django.core.management.base导入BaseCommand,CommandError
导入optpass
类命令(BaseCommand):
args='--datapath=/path/to/text/data/'
是否可以导入\u设置=真
帮助='将扫描文本导入问题和选项'
选项列表=基本命令。选项列表+(
optpasse.make_选项('--datapath',action='store',type='string',
dest='datapath',
help=“要分析的OCRd文本文件的路径”。),
)
需要模型验证=真
#解析器资源
BACKUP\u RE=RE.compile(r'\~$| bak$| back$| BACKUP$)
QUEST_RE=RE.compile(r'^[0-9]{1,3}[.][]')
CHOICE_RE=RE.compile(r'^[a-e][.][.][.]
def句柄(自身、*参数、**选项):
#获取数据路径
尝试:
存在(选项['datapath'])
例外情况除外,如e:
raise CommandError(“未提供路径或提供的路径无效:%s”%e.message)
self.datapath=os.path.expanduser(选项['datapath'])
#从目标文件中的行生成文本字符串列表
self.data_行=[]
对于os.listdir(os.path.join(self.datapath,'questions/')中的fn:
如果自备份搜索(fn):
self.stderr.write(“跳过备份:%s\n”%(fn))
其他:
对于codecs.open(os.path.join(self.datapath,'questions/',fn),'r',encoding='latin-1')中的行:
如果不是自成一体,is_样板(行):
如果不是line.strip()=='':
self.data\u line.append(行)
#-----------------------------------------------------------------------
#---------------------分析文本行并创建问题/选项
#-----------------------------------------------------------------------
cur_quest=无
cur_choice=无
cur_is_quest=False
问题={}
选项={}
对于self.data_行中的行:
如果self.is_问题(行):
[n,txt]=行分割('.',1)
qtext=txt.rstrip()+“”
q=Question.objects.create(text=qtext)
q、 保存()
cur_quest=q.pk
问题[cur_quest]=q
cur_is_quest=True
elif self.is_choice(行):
[n,txt]=行分割('.',1)
num=self.char2dig(n)
ctext=txt.rstrip()+“”
c=Choice.objects.create(text=ctext,order=num,question=questions[cur\u quest])
c、 保存()
cur_choice=c.pk
选项[cur_choice]=c
cur_is_quest=False
其他:
如果cur_是任务:
问题[cur_quest].text+=line.rstrip()+“”
问题[cur_quest].save()
其他:
选项[cur_choice].text+=line.rstrip()+“”
选项[cur_choice].save()
self.stdout.write(“----完成------\n”)
一无所获
定义是一个问题(self,arg_str):
如果self.QUEST\u RE.search(arg\u str):
返回真值
其他:
返回错误
def是您的选择(self,arg_str):
如果自我选择搜索(参数):
返回真值
其他:
返回错误
def char2dig(自身,x):
如果x==“a”:
返回1
如果x==“b”:
返回2
如果x=='c':
返回3
如果x='d':
返回4
如果x=='e':
返回5
def是模板(自身、参数):
样板文件=[u'MFT实践考试',
u'BERKELEY TRAINING ASSOCIATES'+u'\u00A9'+u'2009',
u'BERKELEY TRAINING ASSOCIATES',
u“婚姻和家庭治疗”,
u‘实践考试41’,
u'第0页',u'第1页',u'第2页',u'第3页',u'第4页',
第5页、第6页、第7页、第8页、第9页、,
]
对于样板中的bp:
如果水平距离(bp.encode('utf-8'),arg_str.encode('u
from models import Table1, Table2
from myapp.models import Table1, Table2
export DJANGO_SETTINGS_MODULE=settings
export PYTHONPATH=/path/to/my/site
python myscript.py "$@"