Python 读取\u csv获取发生异常的行

Python 读取\u csv获取发生异常的行,python,pandas,exception,Python,Pandas,Exception,我试图用pandas分析的HTTP日志文件有时会出现意外的行。以下是我加载数据的方式: df = pd.read_csv('mylog.log', sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])', engine='python', na_values=['-'], header=None, usecols=[0, 3, 4, 5, 6, 7, 8,10],

我试图用pandas分析的HTTP日志文件有时会出现意外的行。以下是我加载数据的方式:

df = pd.read_csv('mylog.log',
            sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])', 
            engine='python', na_values=['-'], header=None,
            usecols=[0, 3, 4, 5, 6, 7, 8,10],
            names=['ip', 'time', 'request', 'status', 'size', 
                'referer','user_agent','req_time'], 
                converters={'status': int, 'size': int, 'req_time': int})
它适用于我拥有的大多数日志(来自同一台服务器)。但是,在加载某些日志时,会引发异常: 或者

 TypeError: int() argument must be a string, a bytes-like object or a  number, not 'NoneType'

在本例中,以下是触发第二个异常的行:

22.111.117.229, 22.111.117.229 - - [19/Sep/2018:22:17:40 +0200] "GET /agent/10577/bdl HTTP/1.1" 204 - "-" "okhttp/3.8.0" apibackend.site.fr 429282
为了找到犯罪行的编号,我使用了以下(非常慢)函数:

def search_error_dichotomy(path):    
        borne_inf = 0
        log = open(path)
        borne_sup = len(log.readlines())
        log.close()
        while borne_sup - borne_inf>1:
            exceded = False
            search_index = (borne_inf + borne_sup) // 2
            try:
                pd.read_csv(path,...,...,nrows=search_index)
            except:
                exceded = True
            if exceded:
                borne_sup = search_index
            else:
                borne_inf = search_index

        return search_index
我想要的是这样的:

try:
    pd.read_csv(..........................)
except MyError as e:
    print(e.row_number)
其中e.row_number是混乱行的编号

先谢谢你

解决方案 所有的功劳都归功于devssh,他的建议不仅加快了流程,而且让我能够一次获得所有意想不到的线路。以下是我所做的:

  • 加载不带转换器的数据帧

    df = pd.read_csv(path,
                     sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])', 
                     engine='python', na_values=['-'], header=None,
                     usecols=[0, 3, 4, 5, 6, 7, 8,10],
                     names=['ip', 'time', 'request', 'status', 'size',
                     'referer', 'user_agent', 'req_time'])
    
  • 使用.reset_index()添加“index”列

  • 编写自定义函数(与apply一起使用),如果可能,将其转换为int,否则保存 字典中的条目和“索引”有错误的行

    wrong_lines = {}
    def convert_int_feedback_index(row,col):
        try:
            ans = int(row[col])
        except:
            wrong_lines[row['index']] = row[col]
            ans = pd.np.nan
        return ans
    
  • 对我要转换的列使用apply(例如col='status'、'size'或'req_time')


  • 您是否尝试过
    pd.read_csv(…,nrows=10)
    查看它是否能在10行上运行

    也许您不应该使用
    转换器
    来指定
    数据类型

    加载数据帧,然后将数据类型应用于列,如
    df[“column”]=df[“column”]。astype(np.int64)
    或自定义函数,如
    df[“column”]=df[“column”]。应用(lambda x:convert_type(x))
    并在函数convert_type中自行处理错误。
    最后,通过调用
    df.to_csv(“preprocessed.csv”,headers=True,index=False)更新csv

    我认为您无法从pd.read\u csv本身获取行号。分隔符本身看起来太复杂了

    或者您可以尝试将csv作为单列数据帧读取,然后使用
    df[“column”].str.extract
    使用正则表达式提取列。这样,您可以控制如何引发异常或处理错误的默认值


    df.reset_index()
    将把行号作为列提供给您。这样,如果您选择,您也将获得行号。它将为您提供带有行号的索引列。将其与“应用于多个列”相结合,您可以自定义所有内容。

    有什么例外?@devssh:是的,我尝试了小nrow,错误出现在第271119行。至于删除转换器并使用.astype或.apply,这听起来是个好主意,但我不知道如何检索发生异常的行的编号。你看到我的建议了吗?它将为您提供带有行号的
    索引
    列。将其与多个列上的
    应用相结合,您可以自定义所有内容。使用这种替代方法,您现在似乎可以默认获得行号了,对吗?@devssh:Wow,使用“df.reset_index()”确实可以做到这一点!非常感谢你!
    
    df = df.reset_index()
    
    wrong_lines = {}
    def convert_int_feedback_index(row,col):
        try:
            ans = int(row[col])
        except:
            wrong_lines[row['index']] = row[col]
            ans = pd.np.nan
        return ans
    
    df[col] = df.apply(convert_int_feedback_index, axis=1, col=col)