惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
Scott Helme
Scott Helme
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
P
Privacy & Cybersecurity Law Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
罗磊的独立博客
MyScale Blog
MyScale Blog
博客园 - 【当耐特】
L
LangChain Blog
AWS News Blog
AWS News Blog
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Proofpoint News Feed
T
True Tiger Recordings
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
月光博客
月光博客
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
S
SegmentFault 最新的问题
Recorded Future
Recorded Future
S
Security Archives - TechRepublic
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
Y
Y Combinator Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
博客园 - 聂微东
GbyAI
GbyAI
N
News and Events Feed by Topic
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
博客园 - 三生石上(FineUI控件)
G
Google Developers Blog
A
About on SuperTechFans
K
Kaspersky official blog
NISL@THU
NISL@THU
S
Securelist
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX - 技术

V2EX

[分享创造] 做了一个开源 SSH/SFTP 桌面工具,想解决人和 AI 共用远程上下文的问题 用 DeepSeek 做了个用量页面个小插件, 增加了几个维度的数据统计和计算 [体验分享] 从 TG、Signal 折腾一圈后,还是觉得 WhatsApp 最均衡 💔再见了!北京移动 18 元魔卡月底下架 [酷工作] 百度封控 / 渠道回传 / 无痕浏览 技术需求 [香港] 请问现在去香港还能开到银行卡吗 我开源了一个项目:把任何资料,安全的变成 AI 的上下文 我做了一个给超级个体 / OPC 用的 AI 智能体商业化平台 求推荐靠谱的海外 VPS [投资] 基金可以跑赢银行的贷款利率,那么基金一定靠谱么? 做了一个 Vibe coding 辅助小工具 claude|gpt 被封号的,或者还幸存的来 ai 时代的程序员 怪不得老板喜欢压迫员工,原来这么爽 [生活] 当系统判定“用户永远正确”时,老实人是不是只能认栽? [剧集] 凡人修仙传动画新年番 6 月 13 日上午 11 点开播! [推广] [追加福利!老板还没回] 偷偷再放 4 个独家 CDK, IP/500M 动态流量随缘自取,手慢无! 端午节准备去广州找个地方吃荔枝,大家有推荐的没 非招聘|佛系寻找远程同频开发者,先认识再合作 [问与答] 大伙儿推荐一个入口 IP 在境内的机场 币圈准备做复刻带单了,打不过就加入? 天塌了! Gemini 目前不支持你所在的地区。敬请期待! [问与答] 大佬们,有推荐比较好用的行李箱吗 我给 Claude Code 装了个“红绿灯”,再也不怕忘记确认状态了 Hermes Agent 通过 Webhook 收到消息后,再与用户进行交互会话,就分隔成两个会话了,丢失了上下文,如何解决? [Mac mini] QianPlayer — 给 macOS 写了一个原生视频播放器 年前决定戒烟到现在,顺便做了个小程序。 阿里百炼的自建 DeepSeek 限速是 TPM 1.2M,这限速是拍脑袋的吗? 想问一下上海拿工资的多少百分比租房? 换了个高刷 4k 显示器, c 口只有 15w [开源自荐] 悦心搜索 4.0,网盘搜索引擎,对接盘搜,快速搜索转存 [分享创造] [送会员] 搞了个专业文档转换, 翻译软件, 可一键批量翻译并保持格式,支持 PDF 等多种文档格式 原型设计是否可以直接让 AI 来做? [限时] 6 折招代理~阿里云国际|腾讯云国际 easy-tdx:接手停更的 pytdx,加了 CLI 和 30 个技术指标 [北京] 求租北京新能源指标 外包兼职(长期) [分享创造] 分享一个把微信步数变成修为的小程序:走路涨修为 求 codex、claude code 订阅账单每月$200 的,或者国内 coding 订阅,有偿 [生活] 鼻中隔偏曲术后第 9 天 Fractal Skills:给 AI Agent 一副不会过期的缰绳 vb 了一个图片工具箱,目前实现了拼图和切割图,大家看看怎么样,还花了 375 大洋买了个域名(10 年) 淘宝是不是发狂了?每天打开都要搞一个土鳖特效叫我立即领取 xx 元优惠券,实际上也没优惠什么 开启 Codex 桌宠 [上海] 上海有没有靠谱月嫂推荐? [问与答] 午休求救,要崩溃了 注册送 120 刀的周卡 分享一下我薅的站点 基于本地数据生成 ClaudeCode 热力图 小米大模型降智? 中转站免费 credit 就是电子鸡蛋 [问与答] 大家好,刚进 v 站,有没有大佬给我介绍 v 站的特色啊 阿里云 web 首页疑似会导致 Firefox 占用大量 CPU 资源 [AI Agent 智能体] 越来越怀疑,很多 Agent 现在根本进不了企业 [AI 独角兽团队] 内推直招 | 后端开发工程师,创业早期机会,升职加薪快 AI 写的代码你们是怎么保证质量的? 今天下午 Codex 每问个问题就报 429,大家都这样吗?是不是要出新模型了 [推广] 今天 pp 渠道死了,又是哀嚎遍野 claude 5 小时限额变少了,有没有同感? 安克创新咋了,一天 10 几个猎头狂推给我 Gps 坐标收藏夹 开发者平台,分成规则分享 [问与答] 麻醉是不是最接近死亡的体验? 这两天 Gemini 网页版开始胡说八道了吗? 关于海南求职的付费咨询 自建 VPS 推荐 [职场话题] 作为技术人如何和老板谈项目谈生意? claude code 工作中,切换不同中转站的 api 的不同模型,上下文记忆会丢失吗? [问与答] API 调用 chatgpt 的 这里是知乎吗? [VPS] 像搬瓦工、DMIT 等一般什么时候有优惠呢 [推广] Krill 福利加倍送,持续送,回贴就送,反正就是送~纯 pro 号池低至 0.13, image-2 免费用 , dp-v4-flash 官方 4 折! 大家拳皇和街霸玩的如何?做了一个帮助大家练招的训练工具 Crypto 交易所在线直招 实习生岗位开放 纯远程办公 BD 实习生/ 行研实习生/ 管培生 未来之星选拔计划 [华为] 大家怎么看这几天比较火的华为“韬定律芯片”逻辑折叠技术架构 [iPhone] 请问这个算是 iPhone 被 pdd 劫持了吗? 该走还是继续留 雨刮品牌-博世怎么样? [月末活动] 一个真正一目了然的自建 Codex 中转站 前端失业 2 个月了, 5 月份开始投简历,一共就约到 8 家 想做一个更轻的「友链网络」组件: LinkPals 被领导警告了 [AI Agent 智能体] 为什么我觉得 AI 真正的机会在“数字员工” 我自己感觉 codex 极大的扩展了个人的能力者不用说,但是用多了似乎也会有更多精神问题 把 10.8GB vLLM 镜像的 Pod Ready 从 4m35s 降到 14s: Hermes + SOCI lazy loading 实测 [程序员] 免费共享自己的 token 给大家一起用 极豹代理注册送 500M 动态住宅流量 静态住宅 3 刀起 [Codex] 好像没有人说 ChatGPT 账户登录的 Codex,不支持 GPT-5.3 Codex、GPT-5.4 等模型了 有没有一种工作能每天稳定收入 10-50 元 [分享创造] 谁还记得 K-MeleonCCF 网页浏览器 [分享发现] 从 0 开始 vibe coding,产品上线一个月 1500+用户,我对用户增长的一些思考 [Windows] 卡巴斯基安全软件和卡巴斯基标准版选择哪个? [程序员] 做了一个本地音频处理 + 伪知识库应用,强依赖本地 ASR 模型,这种项目开源有意义吗? [Linux] 国产 Touchpad 在 arch 下偶发无法用手势 [问与答] 有老哥用 Portainer 吗? webhook 调用成功但是没有重新部署,哪位有经验? [问与答] 现在比较可靠的国外手机卡选哪家? [路由器] MikroTik RB5009 在 2026 是否还值得入手 [硬件] 外置硬盘有什么散热的好方案,太热了 OpenCode 的压缩算法有建议的兄弟们吗?主要是写 LaTeX 论文。 今年 618 是凉了吗 现在各类所谓戒网瘾机构真的太吓人了.
使用 pandas 读取 csv 遇到了一些问题,求教
SOSdanOffica · 2025-04-15 · via V2EX

公司有个很简单的需求:

  1. 合并多个 csv 文件.根据时间戳抽取其中一部分并导出
  2. 有 GUI 给其他人使用

我用 python 写了一个脚本,GUI 使用的是 pyqt5

# -*- coding: utf-8 -*-
import sys
import os
import csv
import pandas as pd
from datetime import datetime
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QPushButton, QLineEdit,
    QVBoxLayout, QHBoxLayout, QFileDialog, QDateTimeEdit, QLabel,
    QMessageBox, QProgressBar, QStatusBar,
)
from PyQt5.QtCore import QDateTime
from PyQt5.QtGui import QIntValidator


class CSV_Filter(QMainWindow):  
    def __init__(self):
        super().__init__()
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.init_ui()

    def init_ui(self):
        # 创建组件
        self.input_select_button = QPushButton('浏览...')
        self.input_path_text = QLineEdit()
        self.input_path_text.setReadOnly(True)
        self.datetime_start = QDateTimeEdit()
        self.datetime_end = QDateTimeEdit()
        self.time_diff_input = QLineEdit()
        self.start_button = QPushButton('开始合并')
        self.export_select_button = QPushButton('浏览...')
        self.export_path_text = QLineEdit()
        self.export_path_text.setReadOnly(True)

        # 创建进度条和状态栏
        self.progress_bar = QProgressBar()
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.addPermanentWidget(self.progress_bar)
        self.progress_bar.setValue(0)

        # 设置日期时间选择框
        debug_time = QDateTime(2024, 5, 3, 19, 10)
        self.datetime_start.setDateTime(debug_time)
        self.datetime_end.setDateTime(debug_time)
        #now = QDateTime.currentDateTime()
        #self.datetime_start.setDateTime(now)
        #self.datetime_end.setDateTime(now)
        self.datetime_start.setCalendarPopup(True)
        self.datetime_end.setCalendarPopup(True)
        self.datetime_start.setDisplayFormat("yyyy-MM-dd HH:mm")
        self.datetime_end.setDisplayFormat("yyyy-MM-dd HH:mm")

        self.time_diff_input.setPlaceholderText("输入分钟数")
        self.time_diff_input.setValidator(QIntValidator())
        self.start_button.setEnabled(False)

        layout = QVBoxLayout()
        layout.addWidget(QLabel("选择 log 路径:"))
        input_path_layout = QHBoxLayout()
        input_path_layout.addWidget(self.input_path_text)
        input_path_layout.addWidget(self.input_select_button)
        layout.addLayout(input_path_layout)

        layout.addWidget(QLabel("选择导出路径:"))
        export_path_layout = QHBoxLayout()
        export_path_layout.addWidget(self.export_path_text)
        export_path_layout.addWidget(self.export_select_button)
        layout.addLayout(export_path_layout)

        layout.addWidget(QLabel("开始时间:"))
        layout.addWidget(self.datetime_start)
        layout.addWidget(QLabel("时间差(分钟):"))
        layout.addWidget(self.time_diff_input) 
        layout.addWidget(QLabel("结束时间:"))
        layout.addWidget(self.datetime_end)
        layout.addWidget(self.start_button)

        self.central_widget.setLayout(layout)
        self.setWindowTitle('CSV-Filter')

        self.input_select_button.clicked.connect(self.select_input_folder)
        self.export_select_button.clicked.connect(self.select_export_folder)
        self.start_button.clicked.connect(self.merge_csv)
        self.input_path_text.textChanged.connect(self.check_inputs)
        self.export_path_text.textChanged.connect(self.check_inputs)
        self.datetime_start.dateTimeChanged.connect(self.update_time_diff)
        self.datetime_end.dateTimeChanged.connect(self.update_time_diff)
        self.time_diff_input.textChanged.connect(self.update_end_time_from_diff)

    def select_input_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, '选择 log 所在的文件夹')
        if folder_path:
            self.input_path_text.setText(folder_path)
    
    def select_export_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, '选择导出 log 的文件夹')
        if folder_path:
            self.export_path_text.setText(folder_path)

    def check_inputs(self):
        flag_input = self.input_path_text.text().strip() != ""
        flag_export = self.export_path_text.text().strip() != "" 
        self.start_button.setEnabled(flag_input and flag_export)

    def update_time_diff(self):
        start_time = self.datetime_start.dateTime()
        end_time = self.datetime_end.dateTime()
        time_diff = start_time.secsTo(end_time) / 60
        self.time_diff_input.setText(str(int(time_diff)))

    def update_end_time_from_diff(self):
        try:
            time_diff_minutes = int(self.time_diff_input.text())
            start_time = self.datetime_start.dateTime()
            new_end_time = start_time.addSecs(time_diff_minutes * 60)
            self.datetime_end.setDateTime(new_end_time)
        except ValueError:
            pass

    def merge_csv(self):
        input_path = self.input_path_text.text().strip()
        export_path = self.export_path_text.text().strip()
        start_time = self.datetime_start.dateTime().toPyDateTime()
        end_time = self.datetime_end.dateTime().toPyDateTime()

        csv_files = []
        for root, dirs, files in os.walk(input_path):
            for file in files:
                if file.endswith('.csv'):
                    csv_files.append(os.path.join(root,file))

        if not csv_files:
            QMessageBox.warning(self,"提示","没有找到.csv 文件")
            return

        combined_df = pd.DataFrame()
        total_files = len(csv_files)
        self.progress_bar.setMaximum(total_files)
        self.progress_bar.setValue(0)
        self.status_bar.showMessage("正在处理 CSV 文件...")

        for index, csv_file in enumerate(csv_files, start=1):
            try:
                df = pd.read_csv(csv_file)
                df['Source File'] = csv_file
                df['DATE_TIME'] = pd.to_datetime(
                    df['DATE_TIME'].str.extract(r'\[(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})\]')[0],
                    format='%Y/%m/%d %H:%M:%S',
                    errors='coerce'
                )
                combined_df = pd.concat([combined_df, df], ignore_index=True)
            except Exception as e:
                QMessageBox.warning(self, "读取错误", f"读取文件失败:{csv_file}\n\n 错误信息:{str(e)}")

            self.progress_bar.setValue(index)  # 更新进度条
            QApplication.processEvents()      # 刷新界面

        filtered_df = combined_df[(combined_df['DATE_TIME']>=start_time)&(combined_df['DATE_TIME']<=end_time)]
        filtered_df = filtered_df.sort_values(by='DATE_TIME')
        now = datetime.now()
        timestamp = now.strftime("%Y%m%d_%H%M")
        filename = f"filtered_log_{timestamp}.csv"
        filtered_df.to_csv(os.path.join(export_path,filename),index=False)

        self.status_bar.showMessage("完成!", 3000)
        QMessageBox.information(self, "完成", "已成功导出")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CSV_Filter()
    window.show()
    sys.exit(app.exec_())

但测试的时候发现 csv 数据很不规范

随便抽一条当个例子:

"37929","301","00 40 00 00 00 B9 30 30 3A 30 30 3A 30 32 3A 31 
31 33 20 28 32 34 34 30 29 56 20 65 76 65 6E 74 
20 36 35 30 20 70 75 62 6C 69 63 3A 38 2C 31 20 
30 20 22 64 69 73 6B 3A 38 2C 30 22 20 22 22 0A ","[2025/02/20 12:00:51]","9250","DATA LOG","00:00:02:113 (2440)V event 650 public:8,1 0 "disk:8,0" ""
"

数据应该是 7 列,但是读取到这里就会识别成 8 列然后报错. 我考虑过逐行读取不进行分列,只在其中用正则表达式抽选时间戳新增一列作为筛选的标准. 但因为原始数据中存在换行,这一条数据会被作为好几行读取,导致抽取时的损失

Python 新手,在 Chatgpt 的帮助下完成的,实在没办法了,有没有数据大手子帮忙看看