2014-10-24 4 views
2

Я прочитал несколько статей StackOverflow по этой и большей части из 10 лучших результатов Google. Там, где моя проблема отличается, я использую один скрипт в python для создания файлов JSON. И следующий скрипт, запускаемый не через 10 минут, не может прочитать этот самый файл.Python & JSON: ValueError: Unterminated string, начинающийся с:

Краткая версия, я генерирую потенциальных клиентов для своего онлайн-бизнеса. Я пытаюсь изучить python, чтобы лучше анализировать эти данные. Я стараюсь лидировать на 2 года, имея в виду сохранить полезные данные и удалить все личные - адреса электронной почты, имена и т. Д., А также сохранить 30 000 + приводит к нескольким десяткам файлов для легкого доступа.

Таким образом, мой первый скрипт открывает каждый отдельный файл руководства - 30 000+ - определяет дату его захвата на основе метки времени в файле. Затем это сохраняет, что приводит к соответствующему ключу в dict. Когда все данные были объединены в эти текстовые файлы, они записываются с использованием json.dumps.

Структура Dict является:

addData['lead']['July_2013'] = { ... } 

где ключ «свинец» может быть свинец, частичный, и несколько других, и ключ «July_2013», очевидно, на основе ключевой даты, которая может быть любой комбинацией полный месяц и 2013 или 2014 год, возвращаясь к «февралю_2013».

Полная ошибка заключается в следующем:

ValueError: Unterminated string starting at: line 1 column 9997847 (char 9997846) 

Но я вручную посмотрел на файл и мой IDE говорит, что есть только 76655 символов в файле. Итак, как он добрался до 9997846?

Файл, который выходит из строя, является восьмым для чтения; другие 7 и все другие файлы, которые появляются после его чтения через json.loads, просто прекрасны.

Python говорит, что есть в неисчерпаемой строке, поэтому я посмотрел на конец JSON в файле, который терпит неудачу, и кажется, что все в порядке. Я видел упоминание о том, что новые строки являются \ n в JSON, но эта строка - одна строка. Я видел упоминание о \ vs \, но при быстром просмотре всего файла я не видел. Другие файлы имеют \, и они читаются в порядке. И эти файлы были созданы json.dumps.

Я не могу опубликовать файл, потому что он по-прежнему содержит личную информацию. Вручную попытка проверить JSON из 76 000 char файлов не является реальной жизнеспособностью.

Мысли о том, как отладить это, будут оценены. В то же время я собираюсь попытаться перестроить файлы и посмотреть, не является ли это всего лишь одной ошибкой, но это занимает некоторое время.

  • Python 2.7 с помощью Spyder & Anaconda
  • Windows 7 Pro

--- Редактировать --- По желанию я проводкой писать код здесь:

from p2p.basic import files as f 
from p2p.adv import strTools as st 
from p2p.basic import strTools as s 

import os 
import json 
import copy 
from datetime import datetime 
import time 


global leadDir 
global archiveDir 
global aggLeads 


def aggregate_individual_lead_files(): 
    """ 

    """ 

    # Get the aggLead global and 
    global aggLeads 

    # Get all the Files with a 'lead' extension & aggregate them 
    exts = [ 
     'lead', 
     'partial', 
     'inp', 
     'err', 
     'nobuyer', 
     'prospect', 
     'sent' 
    ] 

    for srchExt in exts: 
     agg = {} 
     leads = f.recursiveGlob(leadDir, '*.cd.' + srchExt) 
     print "There are {} {} files to process".format(len(leads), srchExt) 

     for lead in leads: 
      # Get the Base Filename 
      fname = f.basename(lead) 
      #uniqID = st.fetchBefore('.', fname) 

      #print "File: ", lead 

      # Get Lead Data 
      leadData = json.loads(f.file_get_contents(lead)) 

      agg = agg_data(leadData, agg, fname) 

     aggLeads[srchExt] = copy.deepcopy(agg) 

     print "Aggregate Top Lvl Keys: ", aggLeads.keys() 
     print "Aggregate Next Lvl Keys: " 

     for key in aggLeads: 
      print "{}: ".format(key) 

      for arcDate in aggLeads[key].keys(): 
       print "{}: {}".format(arcDate, len(aggLeads[key][arcDate])) 

     # raw_input("Press Enter to continue...") 


def agg_data(leadData, agg, fname=None): 
    """ 

    """ 
    #print "Lead: ", leadData 

    # Get the timestamp of the lead 
    try: 
     ts = leadData['timeStamp'] 
     leadData.pop('timeStamp') 
    except KeyError: 
     return agg 

    leadDate = datetime.fromtimestamp(ts) 
    arcDate = leadDate.strftime("%B_%Y") 

    #print "Archive Date: ", arcDate 

    try: 
     agg[arcDate][ts] = leadData 
    except KeyError: 
     agg[arcDate] = {} 
     agg[arcDate][ts] = leadData 
    except TypeError: 
     print "Timestamp: ", ts 
     print "Lead: ", leadData 
     print "Archive Date: ", arcDate 
     return agg 

    """ 
    if fname is not None: 
     archive_lead(fname, arcDate) 
    """ 

    #print "File: {} added to {}".format(fname, arcDate) 

    return agg 


def archive_lead(fname, arcDate): 
    # Archive Path 
    newArcPath = archiveDir + arcDate + '//' 

    if not os.path.exists(newArcPath): 
     os.makedirs(newArcPath) 

    # Move the file to the archive 
    os.rename(leadDir + fname, newArcPath + fname) 


def reformat_old_agg_data(): 
    """ 

    """ 

    # Get the aggLead global and 
    global aggLeads 
    aggComplete = {} 
    aggPartial = {} 

    oldAggFiles = f.recursiveGlob(leadDir, '*.cd.agg') 
    print "There are {} old aggregate files to process".format(len(oldAggFiles)) 

    for agg in oldAggFiles: 
     tmp = json.loads(f.file_get_contents(agg)) 

     for uniqId in tmp: 
      leadData = tmp[uniqId] 

      if leadData['isPartial'] == True: 
       aggPartial = agg_data(leadData, aggPartial) 
      else: 
       aggComplete = agg_data(leadData, aggComplete) 

    arcData = dict(aggLeads['lead'].items() + aggComplete.items()) 
    aggLeads['lead'] = arcData 

    arcData = dict(aggLeads['partial'].items() + aggPartial.items()) 
    aggLeads['partial'] = arcData  


def output_agg_files(): 
    for ext in aggLeads: 
     for arcDate in aggLeads[ext]: 
      arcFile = leadDir + arcDate + '.cd.' + ext + '.agg' 

      if f.file_exists(arcFile): 
       tmp = json.loads(f.file_get_contents(arcFile)) 
      else: 
       tmp = {} 

      arcData = dict(tmp.items() + aggLeads[ext][arcDate].items()) 

      f.file_put_contents(arcFile, json.dumps(arcData)) 


def main(): 
    global leadDir 
    global archiveDir 
    global aggLeads 

    leadDir = 'D://Server Data//eagle805//emmetrics//forms//leads//' 
    archiveDir = leadDir + 'archive//' 
    aggLeads = {} 


    # Aggregate all the old individual file 
    aggregate_individual_lead_files() 

    # Reformat the old aggregate files 
    reformat_old_agg_data() 

    # Write it all out to an aggregate file 
    output_agg_files() 


if __name__ == "__main__": 
    main() 

Здесь - код считывания:

from p2p.basic import files as f 
from p2p.adv import strTools as st 
from p2p.basic import strTools as s 

import os 
import json 
import copy 
from datetime import datetime 
import time 


global leadDir 
global fields 
global fieldTimes 
global versions 


def parse_agg_file(aggFile): 
    global leadDir 
    global fields 
    global fieldTimes 

    try: 
     tmp = json.loads(f.file_get_contents(aggFile)) 
    except ValueError: 
     print "{} failed the JSON load".format(aggFile) 
     return False 

    print "Opening: ", aggFile 

    for ts in tmp: 
     try: 
      tmpTs = float(ts) 
     except: 
      print "Timestamp: ", ts 
      continue 

     leadData = tmp[ts] 

     for field in leadData: 
      if field not in fields: 
       fields[field] = [] 

      fields[field].append(float(ts)) 


def determine_form_versions(): 
    global fieldTimes 
    global versions 

    # Determine all the fields and their start and stop times 
    times = [] 
    for field in fields: 
     minTs = min(fields[field]) 
     fieldTimes[field] = [minTs, max(fields[field])] 
     times.append(minTs) 
     print 'Min ts: {}'.format(minTs) 

    times = set(sorted(times)) 
    print "Times: ", times 
    print "Fields: ", fieldTimes 

    versions = {} 
    for ts in times: 
     d = datetime.fromtimestamp(ts) 
     ver = d.strftime("%d_%B_%Y") 

     print "Version: ", ver 

     versions[ver] = [] 
     for field in fields: 
      if ts in fields[field]: 
       versions[ver].append(field) 


def main(): 
    global leadDir 
    global fields 
    global fieldTimes 

    leadDir = 'D://Server Data//eagle805//emmetrics//forms//leads//' 
    fields = {} 
    fieldTimes = {} 

    aggFiles = f.glob(leadDir + '*.lead.agg') 

    for aggFile in aggFiles: 
     parse_agg_file(aggFile) 

    determine_form_versions() 

    print "Versions: ", versions 




if __name__ == "__main__": 
    main() 
+0

Вам нужно будет указать нам свой код. Если у него есть личная информация, удалите информацию. – jwodder

+0

Вы действительно хотите, чтобы я опубликовал файл JSON с 76 000 символов? Код работает для каждого другого файла, но это. Поэтому я уверен, что это имеет какое-то отношение к одному из полей, которые были сохранены. Он содержит личную информацию о нескольких тысячах человек. Я мог вручную вводить данные в новый файл почти так же быстро, как я мог удалить эти личные данные из этого. И если PHP или что-то не откроет этот файл, удаление должно быть выполнено вручную. Если никто не может предоставить указатели без полного файла, я удалю вопрос. –

+0

Нет, я попросил вас показать нам свой * код * - Python, а не JSON. – jwodder

ответ

8

Итак, я понял это ... Я отправляю этот ответ на случай, если кто-то другой сделает ту же ошибку.

Во-первых, я нашел работу, но я не был уверен, почему это сработало. Из моего оригинального кода, вот моя file_get_contents функция:

def file_get_contents(fname): 
    if s.stripos(fname, 'http://'): 
     import urllib2 
     return urllib2.urlopen(fname).read(maxUrlRead) 
    else: 
     return open(fname).read(maxFileRead) 

Я использовал его с помощью:

tmp = json.loads(f.file_get_contents(aggFile)) 

Это не удалось, снова и снова и снова. Однако, поскольку я пытался получить Python, чтобы хотя бы дать мне строку JSON для проверки подлинности JSON (http://jsonlint.com/), я наткнулся на упоминание json.load vs json.loads. Так что я попытался вместо этого:

a = open('D://Server Data//eagle805//emmetrics//forms//leads\July_2014.cd.lead.agg') 
b = json.load(a) 

В то время как я не проверял этот вывод в моем общем коде этот код кусок делает фактически прочитать в файле декодирования JSON, и даже отображать данные без сбоев Spyder. Проводник переменных в Spyder показывает, что b является типом размера 1465, и именно столько записей оно должно иметь. Часть отображаемого текста с конца dict все выглядит хорошо. Таким образом, в целом я уверенно уверен, что данные были проанализированы правильно.

Когда я написал функцию file_get_contents, я увидел несколько рекомендаций, в которых я всегда предоставляю максимальное количество байтов для чтения, чтобы предотвратить зависание Python при плохом возврате. Значение maxReadFile было 1E7. Когда я вручную вынудил maxReadFile быть 1E9 все работало нормально. Оказывается, файл находится под 1,2E7 байт. Таким образом, полученная строка от чтения файла не была полной строкой в ​​файле и в результате была недействительной JSON.

Обычно я бы подумал, что это ошибка, но ясно, что при открытии и чтении файла вы должны иметь возможность читать только кусок за раз для управления памятью. Таким образом, я получил свою близорукость по отношению к значению maxReadFile. Сообщение об ошибке было правильным, но отправил меня на дикую охоту на гусей.

Надеюсь, это сэкономит кому-то еще некоторое время.

3

У меня такая же проблема. Как оказалось, последняя строка файла была неполной, вероятно, из-за резкой остановки загрузки, поскольку я обнаружил, что было достаточно данных и просто остановил процесс на терминале.

Смежные вопросы