当前位置:首页>java>电子发票 PDF 自动解析:新版代码 vs 旧文实现的深度对比

电子发票 PDF 自动解析:新版代码 vs 旧文实现的深度对比

  • 2026-01-14 05:17:21
电子发票 PDF 自动解析:新版代码 vs 旧文实现的深度对比

之前文章中,曾分享了一套简洁的 Python 代码,用于自动解析电子发票 PDF 文件,提取发票号码、税号、金额、名称等关键字段,并一键导出 Excel 表格。这套方案在实际业务中相信能帮助提升发票处理的效率。

但在获得热心读者给的发票样本后,发现原有代码在系统稳健性、字段清洗、项目名称识别等方面显得力不从心。因此,我重新设计了一套更智能、更稳定的发票解析逻辑,并在本文中进行详细讲解。(如需直接运行版本,请看:电子普票智能汇总工具 exe 版

下文将逐步拆解新版代码的每一个字段提取逻辑,并与旧版进行对比,帮助你理解背后的设计思路和实际效果。文章最后附上完整代码,方便你直接使用或二次开发。


快速对比总览
维度
旧文实现
最新代码
规则集中管理
REGEX_PATTERNS 配置集中,解析规则统一入口
以函数(def)为中心,规则分散在具体提取函数中
名称解析
纯正则:buyer_name/seller_name 两条规则
多级策略:精确正则 → 公司关键词候选 → 兜底匹配
税号解析
一次 findall,顺序填充买方/卖方
过滤与去重:剔除发票号干扰,保留有效税号
金额/税额
表格优先,文本兜底(两套 pattern
同样两路解析;更宽容于合计行文本结构
价税合计
单一 regex 捕捉,兼容逗号格式
多模式(含“(小写)”“¥”等),自适应尾段定位
UI 与流程
简洁 Tkinter,两步操作
增加进度条与百分比反馈
输出列
固定列 OUTPUT_COLUMNS
加入“项目名称”列,方便归类会计科目
日期处理
normalize_date 标准化到 
同步标准化处理
架构风格
“配置区 处理类 UI”三段式
工具函数 处理类 UI,更偏函数式拆分


新代码的核心改进

  • 名称解析更稳:不再只靠一条正则,增加公司/机构类关键词扫描和兜底匹配,显著提升购买方/销售方识别成功率。

  • 税号提取更干净:过滤掉“纯数字且与发票号有包含关系”的串,避免把20位发票号也当税号。

  • 价税合计更兼容:在票面下半部分重点搜索,兼容“(小写)”“¥”,“,”,“,”等不同写法。

  • 项目名称新增且去噪:支持星号(“*”)结构、跨行拼接、尾部型号括号按需保留,并清理数字/小写英文噪音。

  • UI 体验升级:进度条 + 百分比,跑批过程更透明;完成后自动打开 Excel。


解析逻辑拆解与示例代码

发票号码与开票日期

  • 发票号码:

    通过 re.findall(r"\d{20}", text) 抓取 20 位数字,取第一个即可。旧文将正则放在 REGEX_PATTERNS,逻辑等价

  • 开票日期:
    有改良的是包容了空格,从而匹配好“YYYY年MM月DD日”,再标准化为 “YYYY-MM-DD”。旧文同样在导出前统一格式
invoice_numbers = re.findall(r"\d{20}", text)data["发票号码"] = invoice_numbers[0if invoice_numbers else "未识别"date_match = re.search(r"(\d{4}\s*年\s*\d{1,2}\s*月\s*\d{1,2}\s*日)", text)data["开票日期"] = date_match.group(1if date_match else "未识别"
  • 要点

      • 容错:

        一些地区会有“-”或“/”日期写法,或者当中有空格,标准化函数里已兼容。

      • 顺序:

        先解析原始文本,再用归一化函数统一到 Excel。

税号提取与去重

  • 旧文做法:

    统一社会信用代码/纳税人识别号,一次 findall,然后按出现顺序填充买方/卖方

  • 新版改进:
    过滤掉纯数字且被发票号码包含的字符串,避免误判。
def extract_tax_ids(text: str, invoice_numbers: list[str]) -> tuple[strstr]:    tax_ids = re.findall(r"[0-9A-Z]{18}", text)    clean_tax_ids = [        tid for tid in tax_ids        if not (tid.isdigit() and any(tid in inv for inv in invoice_numbers))    ]    buyer = clean_tax_ids[0if len(clean_tax_ids) > 0 else "未识别"    seller = clean_tax_ids[1if len(clean_tax_ids) > 1 else "未识别"    return buyer, seller
  • 要点

      • 长度与字符集:

        大多数税号是 18 位的字母数字组合。

      • 干扰排除:

        发票号也是长串数字,必须明确区分

购买方/销售方名称解析(重点)

  • 旧文:

    靠两条正则做分界,简洁但容易吃到噪音

  • 新版:
    三层策略,先精确匹配,再按公司/机构关键词收集候选,最后兜底。
def extract_names(text: str) -> tuple[strstr]:    buyer, seller = "未识别""未识别"    # 1. 精确匹配买方/卖方    m_buyer = re.search(r"名称[::]?\s*([^\n]+?)(?=销\s*名称[::])", text, re.S)    m_seller = re.search(r"销\s*名称[::]?\s*([^\n]+)", text)    if m_buyer: buyer = m_buyer.group(1).strip()    if m_seller: seller = m_seller.group(1).strip()    # 2. 如果未识别,逐行扫描公司/机构关键词    if "未识别" in (buyer, seller):        candidates = []        for line in text.splitlines():            matches = re.findall(                r"(?:名称[::]?\s*)?([\u4e00-\u9fffA-Za-z0-9()()]+"                r"(?:公司|院|厂|店|中心|协会|研究所|学校|大学|医院|银行|合作社|集团))",                line            )            candidates.extend(matches)        if buyer == "未识别" and len(candidates) >= 1:            buyer = candidates[0].strip()        if seller == "未识别" and len(candidates) >= 2:            seller = candidates[1].strip()    # 3. 最后兜底:全局找“名称”字段    if "未识别" in (buyer, seller):        names = re.findall(r"名称[::]?\s*([^\n]+)", text)        if buyer == "未识别" and len(names) >= 1:            buyer = names[0].strip()        if seller == "未识别" and len(names) >= 2:            seller = names[1].strip()    return buyer, seller
  • 要点

      • 分层策略:

        先精准,后泛化,最后兜底,避免“一把梭”导致误判。

      • 关键词库:

        “公司、集团、中心、研究所”等能显著提高召回率。

金额与税额(表格优先,文本兜底)

  • 旧文思路:先找表格“合计”行,用“¥数字”抓取;不行再走文本“合计 … ¥金额 ¥税额”。新代码延续同样策略。

def extract_amount_and_tax(text: str, tables: list) -> tuple[strstr]:    for table in tables:        for row in table:            if any("合" in str(c) and "计" in str(c) for c in row if c):                nums = re.findall(r"[¥\u00A5]\s*([0-9.]+)"" ".join(str(c) for c in row if c))                if nums:                    return nums[0], nums[1if len(nums) > 1 else "未识别"    match = re.search(r"合\s*计.*?[¥\u00A5]\s*([0-9.]+).*?[¥\u00A5]\s*([0-9.]+)", text.replace("\n"""))    if matchreturn match.group(1), match.group(2)    return "未识别""未识别"
  • 要点

      • 先结构化后文本:

        表格更稳定,文本更宽容,组合使用成功率高。

      • 兼容符号:

        支持全角/半角的人民币符号。

金额与税额提取:表格优先 + 文本兜底

  • 旧文:

    单条 regex 捕获,兼容逗号

  • 新版:
    采用了“两步走”的策略:先尝试从表格中获取,如果失败再退而求其次用全文正则匹配。这样设计的好处是既能保证准确性,又能提升鲁棒性(健壮性),适配不同版式的发票。
# 价税合计def extract_total_amount(text: str) -> str:    lines = text.splitlines()    total_lines = len(lines)    if total_lines <= 8:        return "未识别"    # 只搜索文本后 40% 区域(即 60% 之后)    start = int(total_lines * 0.6)    search_text = "\n".join(lines[start:])    # 主正则:锁定「(小写)」行,必须有小数点    pattern = r"[((]\s*小写\s*[))]\s*[¥\u00A5]?\s*([\d\s,]+\.\d+)"    total_match = re.search(pattern, search_text)    if total_match:        cleaned = total_match.group(1).replace(",""").replace(" """)        return cleaned.rstrip(".")    else:        # 兜底:取 60% 之后所有带小数点嘅数字,选最大值        candidates = []        for m in re.finditer(r"([\d\s,]+\.\d+)", search_text):            num_str = m.group(1).replace(",""").replace(" """)            if num_str.replace(".""").isdigit():                candidates.append(float(num_str))        return str(max(candidates)) if candidates else "未识别"
  • 逻辑解析
  1. 表格优先

    • 遍历 PDF 中的表格,寻找包含“合计”的行。

    • 如果找到,就用正则匹配人民币符号后的数字,依次作为金额和税额。

    • 这种方式在票据表格结构清晰时最准确。

  2. 文本兜底

    • 如果表格中没有识别到金额或税额,代码会退而求其次,在全文中搜索“合计 ¥金额 ¥税额”的模式。

    • 即使表格解析失败,也能通过文本匹配得到结果。

  3. 最终兜底

    • 如果两种方式都失败,就返回“未识别”,避免程序报错。

    • 这样保证了程序在任何情况下都能稳定运行。

设计亮点

  • 鲁棒性提升:兼容不同票据版式,避免单一正则导致识别失败。

  • 逻辑清晰:分层处理,先表格、后文本、最后兜底。

  • 可维护性强:未来如果需要支持更多票据格式,只需在对应层增加新的匹配规则。

 项目名称(新增字段,智能清洗)

  • 新增意义:发票条目的星号结构经常表达具体服务或货物名称,根据读者提示,有助会计科目的分类。

  • 策略:识别带两个及以上星号的行,拼接下一行,兼容括号型号;清理中间和尾部数字、小写英文、空格。

def extract_project_name(text: str) -> str:    project_name = "未识别"    lines = text.splitlines()    # 全局找含有 ≥2 个 * 的行    star_line_idx = -1    raw_star_line = ""    for idx, line in enumerate(lines):        stripped = line.strip()        if stripped.count("*") >= 2 and re.search(r"[\u4e00-\u9fff]", stripped):            star_line_idx = idx            raw_star_line = stripped            break    if star_line_idx != -1:        candidate_parts = [raw_star_line]        if star_line_idx + 1 < len(lines):            next_line = lines[star_line_idx + 1].strip()            if next_line:                candidate_parts.append(next_line)        candidate_raw = " ".join(candidate_parts)        m = re.search(r"(\*[^*]+\*[^ ()]+)\s*(\([^)]*\)[\u4e00-\u9fff]+)$", candidate_raw)        if m:            project_name = m.group(1) + " " + m.group(2)        else:            project_name = candidate_raw        spaces = [i for i, ch in enumerate(project_name) if ch == " "]        if len(spaces) >= 2:            first_space = spaces[0]            second_last_space = spaces[-2]            project_name = project_name[:first_space] + " " + project_name[second_last_space+1:]    # 清洗噪音    project_name = re.sub(r"\s¥?\d+(?:\.\d+)?%?\s"" ", project_name)    project_name = re.sub(r"\s¥?\d+(?:\.\d+)?%?$""", project_name)    project_name = re.sub(r"\s*[a-z]+$""", project_name)    project_name = re.sub(r"\s+""", project_name)    return project_name
  • 要点

      • 星号结构:

        发票条目通常为“类别细项”,用它锚定更可靠。

      • 清洗顺序:

        先拼接,后截断,再去噪,保证最终可读。


流程与集成:批量、进度、导出

  • 批量处理:递归扫描文件夹,逐张解析,收集成列表。旧文采用同样思路

  • 进度反馈:新增进度条与百分比,跑批心理预期更明确。

  • 导出 Excel:清理名称空白、日期标准化、固定列顺序、保存到桌面并自动打开。

  • 个性化建议

      • 列名锁定:如经常需要“开票人/收款人/备注”等,建议把列顺序和新增列抽到配置,便于扩展。

      • Excel 体验:可增加冻结首行、自动筛选、列宽自适应,提升业务使用体验。


从旧文迁移到新版的实用指引

  • 规则位置变化:

    旧文全部集中在 REGEX_PATTERNS;新版把规则拆到函数里,便于按功能演化(比如项目名称的多步策略)

  • 字段一致性:
    旧文输出列为 10 项;新版新增“项目名称”,可按实际需要决定是否保留
  • 稳定性升级:新版在名称、税号、价税合计上都更“抗噪音”,适合多版式与不同地区票样。

  • 维护方式:

    • 新增版式适配:直接在相应提取函数添加一个新的 pattern,而不必修改全局配置。

    • 回归测试:把历史 PDF 当回归集,逐步验证每次调整不破坏既有识别率。

旧文的结构设计(配置区/处理类/UI)很利于教学和快速上手;新版的函数式拆解则更贴近长期维护和复杂票样适配的需求

完整最新代码(可直接运行)

import pdfplumberimport reimport pandas as pdimport osimport tkinter as tkfrom tkinter import filedialog, messagebox, ttkimport subprocessimport sys# =========================# 工具函数# =========================# 日期标准化函数def normalize_date(date_str):    if date_str == "未识别":        return date_str    date_str = re.sub(r"\s+""", date_str)    formats = [        r"(\d{4})年(\d{1,2})月(\d{1,2})日",        r"(\d{4})[-/](\d{1,2})[-/](\d{1,2})日?"    ]    for fmt in formats:        match = re.match(fmt, date_str)        if match:            return f"{match.group(1)}-{int(match.group(2)):02d}-{int(match.group(3)):02d}"    return date_str# 税号提取def extract_tax_ids(text: str, invoice_numbers: list[str]) -> tuple[strstr]:    tax_ids = re.findall(r"[0-9A-Z]{18}", text)    clean_tax_ids = [tid for tid in tax_ids if not (tid.isdigit() and any(tid in inv for inv in invoice_numbers))]    buyer = clean_tax_ids[0if len(clean_tax_ids) > 0 else "未识别"    seller = clean_tax_ids[1if len(clean_tax_ids) > 1 else "未识别"    return buyer, seller# 名称提取def extract_names(text: str) -> tuple[strstr]:    buyer, seller = "未识别""未识别"    # 1. 精确匹配买方/卖方    m_buyer = re.search(r"名称[::]?\s*([^\n]+?)(?=销\s*名称[::])", text, re.S)    m_seller = re.search(r"销\s*名称[::]?\s*([^\n]+)", text)    if m_buyer: buyer = m_buyer.group(1).strip()    if m_seller: seller = m_seller.group(1).strip()    # 2. 如果未识别,逐行扫描公司/机构关键词    if "未识别" in (buyer, seller):        candidates = []        for line in text.splitlines():            matches = re.findall(                r"(?:名称[::]?\s*)?([\u4e00-\u9fffA-Za-z0-9()()]+"                r"(?:公司|院|厂|店|中心|协会|研究所|学校|大学|医院|银行|合作社|集团))",                line            )            candidates.extend(matches)        if buyer == "未识别" and len(candidates) >= 1:            buyer = candidates[0].strip()        if seller == "未识别" and len(candidates) >= 2:            seller = candidates[1].strip()    # 3. 最后兜底:全局找“名称”字段    if "未识别" in (buyer, seller):        names = re.findall(r"名称[::]?\s*([^\n]+)", text)        if buyer == "未识别" and len(names) >= 1:            buyer = names[0].strip()        if seller == "未识别" and len(names) >= 2:            seller = names[1].strip()    return buyer, seller# 价税合计def extract_total_amount(text: str) -> str:    lines = text.splitlines()    total_lines = len(lines)    if total_lines <= 8:        return "未识别"    # 只搜索文本后 40% 区域(即 60% 之后)    start = int(total_lines * 0.6)    search_text = "\n".join(lines[start:])    # 主正则:锁定「(小写)」行,必须有小数点    pattern = r"[((]\s*小写\s*[))]\s*[¥\u00A5]?\s*([\d\s,]+\.\d+)"    total_match = re.search(pattern, search_text)    if total_match:        cleaned = total_match.group(1).replace(",""").replace(" """)        return cleaned.rstrip(".")    else:        # 兜底:取 60% 之后所有带小数点嘅数字,选最大值        candidates = []        for m in re.finditer(r"([\d\s,]+\.\d+)", search_text):            num_str = m.group(1).replace(",""").replace(" """)            if num_str.replace(".""").isdigit():                candidates.append(float(num_str))        return str(max(candidates)) if candidates else "未识别"# 金额 / 税额def extract_amount_and_tax(text: str, tables: list) -> tuple[strstr]:    for table in tables:        for row in table:            if any("合" in str(c) and "计" in str(c) for c in row if c):                nums = re.findall(r"[¥\u00A5]\s*([0-9.]+)"" ".join(str(c) for c in row if c))                if nums:                    return nums[0], nums[1if len(nums) > 1 else "未识别"    match = re.search(r"合\s*计.*?[¥\u00A5]\s*([0-9.]+).*?[¥\u00A5]\s*([0-9.]+)", text.replace("\n"""))    if matchreturn match.group(1), match.group(2)    return "未识别""未识别"# 项目名称(支持换行 + 全局搜索 + 智能清洗)def extract_project_name(text: str) -> str:    """    从发票文本中提取项目名称(支持换行 + 全局搜索 + 智能清洗)。        参数:text (str): 发票完整文本        返回:str: 项目名称,未识别时返回 "未识别"    """    project_name = "未识别"    lines = text.splitlines()    # 步骤1:全局找含有 ≥2 个 * 的行    star_line_idx = -1    raw_star_line = ""    for idx, line in enumerate(lines):        stripped = line.strip()        if stripped.count("*") >= 2 and re.search(r"[\u4e00-\u9fff]", stripped):            star_line_idx = idx            raw_star_line = stripped            break    if star_line_idx != -1:        # 当前行 + 下一行(只要有内容就拼接,用空格连接)        candidate_parts = [raw_star_line]        if star_line_idx + 1 < len(lines):            next_line = lines[star_line_idx + 1].strip()            if next_line:                candidate_parts.append(next_line)        candidate_raw = " ".join(candidate_parts)        # 提取星号结构 + 尾部(括号型号 + 中文)        m = re.search(r"(\*[^*]+\*[^ ()]+)\s*(\([^)]*\)[\u4e00-\u9fff]+)$", candidate_raw)        if m:            project_name = m.group(1) + " " + m.group(2)        else:            project_name = candidate_raw        # 倒数第二个空格截断        spaces = [i for i, ch in enumerate(project_name) if ch == " "]        if len(spaces) >= 2:            first_space = spaces[0]            second_last_space = spaces[-2]   # 倒数第二个空格            project_name = project_name[:first_space] + " " + project_name[second_last_space+1:]    # 清洗噪音    project_name = re.sub(r"\s¥?\d+(?:\.\d+)?%?\s"" ", project_name)   # 中间数字    project_name = re.sub(r"\s¥?\d+(?:\.\d+)?%?$""", project_name)     # 尾部数字    project_name = re.sub(r"\s*[a-z]+$""", project_name)               # 尾部英文小写    project_name = re.sub(r"\s+""", project_name)                      # 去掉所有空格    return project_name# =========================# 发票处理类# =========================class InvoiceProcessor:    def __init__(self, folder, progress_callback=None, log_callback=None):        self.folder = folder        self.progress_callback = progress_callback        self.log_callback = log_callback        self.invoice_list = []    def log(self, msg):        if self.log_callback:            self.log_callback(msg)        else:            print(msg)    def collect_pdfs(self):        return [            os.path.join(root, f)            for root, _, files in os.walk(self.folder)            for f in files            if f.lower().endswith(".pdf")        ]    def extract_text_and_tables(self, pdf_path):        try:            with pdfplumber.open(pdf_path) as pdf:                full_text = "\n".join(page.extract_text() or "" for page in pdf.pages)                tables = [page.extract_table() for page in pdf.pages if page.extract_table()]            return full_text, tables        except Exception as e:            self.log(f"无法读取文件 {pdf_path}{e}")            return NoneNone    def parse_invoice_info(self, text, tables):        data = {}        invoice_numbers = re.findall(r"\d{20}", text)        data["发票号码"] = invoice_numbers[0if invoice_numbers else "未识别"        date_match = re.search(r"(\d{4}\s*年\s*\d{1,2}\s*月\s*\d{1,2}\s*日)", text)        data["开票日期"] = date_match.group(1if date_match else "未识别"        data["购买方税号"], data["销售方税号"] = extract_tax_ids(text, invoice_numbers)        data["购买方名称"], data["销售方名称"] = extract_names(text)        data["金额"], data["税额"] = extract_amount_and_tax(text, tables)                data["价税合计"] = extract_total_amount(text)        data["项目名称"] = extract_project_name(text)        return data    def process_all_invoices(self):        pdf_files = self.collect_pdfs()        total = len(pdf_files)        for idx, pdf_path in enumerate(pdf_files, 1):            self.log(f"解析文件: {pdf_path}")            text, tables = self.extract_text_and_tables(pdf_path)            if text:                info = self.parse_invoice_info(text, tables)                info["文件名"] = os.path.basename(pdf_path)                self.invoice_list.append(info)            if self.progress_callback:                self.progress_callback(idx, total)    def save_to_excel(self, output_filename="发票汇总.xlsx"):        if not self.invoice_list:            messagebox.showwarning("提示""无有效数据可导出")            return        df = pd.DataFrame(self.invoice_list)        # 清理名称空白        df["购买方名称"] = df["购买方名称"].str.replace(r"\s+""", regex=True)        df["销售方名称"] = df["销售方名称"].str.replace(r"\s+""", regex=True)        # 日期标准化        df["开票日期"] = df["开票日期"].apply(normalize_date)        # 排序        df = df.sort_values("开票日期")        # 列顺序(新增“项目名称”)        ordered_cols = [            "文件名""发票号码""开票日期",            "购买方名称""项目名称""购买方税号",            "销售方名称""销售方税号",            "金额""税额""价税合计"        ]        df = df[ordered_cols]        # 输出路径        desktop = os.path.join(os.path.expanduser("~"), "Desktop")        output_path = os.path.join(desktop, output_filename)        with pd.ExcelWriter(output_path, engine="openpyxl"as writer:            # 总表            df.to_excel(writer, sheet_name="总表", index=False)        # 打开文件        if sys.platform.startswith("win"):            os.startfile(output_path)        elif sys.platform == "darwin":            subprocess.call(["open", output_path])        else:            subprocess.call(["xdg-open", output_path])# =========================# Tkinter UI# =========================class InvoiceUI:    def __init__(self, root):        self.root = root        self.root.title("发票处理工具")        self.root.geometry("390x150+590+350")        tk.Label(root, text="选择文件夹:").grid(row=0, column=0, padx=10, pady=10, sticky="w")        self.entry_folder = tk.Entry(root, width=39)        self.entry_folder.grid(row=0, column=1, padx=10, pady=10, sticky="we")        tk.Button(root, text="浏览", command=self.browse_folder, width=12).grid(row=0, column=2, padx=10, pady=10)        tk.Label(root, text="进度:").grid(row=1, column=0, padx=10, pady=10, sticky="w")        self.progress_var = tk.DoubleVar()        ttk.Progressbar(root, variable=self.progress_var, maximum=100).grid(            row=1, column=1, padx=10, pady=10, sticky="we"        )        self.lbl_percent = tk.Label(root, text="0%")        self.lbl_percent.grid(row=1, column=2, padx=10, pady=10)        tk.Button(root, text="导出发票汇总", command=self.export_invoices, width=12).grid(            row=1, column=0, padx=10, pady=10, sticky="w"        )        root.grid_columnconfigure(1, weight=1)    def browse_folder(self):        folder = filedialog.askdirectory()        if folder:            self.entry_folder.delete(0, tk.END)            self.entry_folder.insert(0, folder)    def export_invoices(self):        folder = self.entry_folder.get().strip()        if not folder or not os.path.exists(folder):            messagebox.showerror("错误""请选择有效的文件夹")            return        processor = InvoiceProcessor(folder, progress_callback=self.update_progress)        processor.process_all_invoices()        processor.save_to_excel("发票汇总.xlsx")        messagebox.showinfo("完成""发票解析并导出完成!")    def update_progress(self, idx, total):        percent = int(idx / total * 100if total else 0        self.progress_var.set(percent)        self.lbl_percent.config(text=f"{percent}%")        self.root.update_idletasks()if __name__ == "__main__":    root = tk.Tk()    app = InvoiceUI(root)    root.mainloop()


结语

不为了炫技巧,而是要让复杂的真实票样都能跑得稳、导得准。这版代码的每一处“啰嗦”,都是为了一线的落地可靠。如果希望把“项目名称”“Excel 交互体验”等再拉满,这里有个直接使用版可以看看

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-09 00:06:51 HTTP/2.0 GET : https://f.mffb.com.cn/a/461708.html
  2. 运行时间 : 0.162346s [ 吞吐率:6.16req/s ] 内存消耗:4,681.92kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3f9ddac90d10b74ba991b7831db16844
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000798s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000928s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000323s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000308s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000534s ]
  6. SELECT * FROM `set` [ RunTime:0.000175s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000592s ]
  8. SELECT * FROM `article` WHERE `id` = 461708 LIMIT 1 [ RunTime:0.002037s ]
  9. UPDATE `article` SET `lasttime` = 1770566811 WHERE `id` = 461708 [ RunTime:0.002957s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 65 LIMIT 1 [ RunTime:0.000250s ]
  11. SELECT * FROM `article` WHERE `id` < 461708 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000361s ]
  12. SELECT * FROM `article` WHERE `id` > 461708 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003652s ]
  13. SELECT * FROM `article` WHERE `id` < 461708 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000724s ]
  14. SELECT * FROM `article` WHERE `id` < 461708 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000977s ]
  15. SELECT * FROM `article` WHERE `id` < 461708 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001375s ]
0.165981s