能兼容大部分情况吧。。。。
pythonimport pdfplumber
import pandas as pd
import os
import re
import pymysql
import sys
import time
'''
错误代码定义:
sys.exit(1)
0:正常结束
1:参数传递错误
2:不是PDF文件
3:无法提取数据
4:数据库保存失败
'''
def extract_data_from_pdf_by_position(pdf_path):
all_data = []
base_data_from_first_page = {}
file_name = os.path.basename(pdf_path)
base_data_from_first_page['文件名'] = file_name
found_base_data_page_index_in_valid_pages = -1 # 在有效页面列表中的索引
valid_pages = [] # 存储有效的报关单页面对象
try:
with pdfplumber.open(pdf_path) as pdf:
# 筛选有效页面 (例如,横向页面,或者包含特定关键字的页面)
for page_obj in pdf.pages:
# 简单判断:横向页面通常 width > height
if page_obj.width > page_obj.height: # 报关单都是横向的
# 进一步检查,例如尝试提取一个非常小但关键的区域,看是否有内容
# 比如尝试提取 “预录入编号” 标签附近的一小块区域
try:
# 这是一个示例坐标
# 目标是找到一个在所有报关单页面上都存在的、小范围的、有文字的区域
# 如果是空白页或完全不相关的页面,这里很可能提取不到有意义的文本
test_crop_coord = (80, 70, 170, 90) # 预录入编号标签附近
if not (test_crop_coord[0] < page_obj.width and test_crop_coord[2] < page_obj.width and \
test_crop_coord[1] < page_obj.height and test_crop_coord[3] < page_obj.height):
# print(f"页面 {page_obj.page_number} 测试坐标超出,跳过此页")
continue
test_text = page_obj.crop(test_crop_coord).extract_text()
if test_text and test_text.strip():
valid_pages.append(page_obj)
# else:
# print(f"页面 {page_obj.page_number} 测试区域无文本,跳过此页")
except Exception as e:
# print(f"页面 {page_obj.page_number} 有效性检查时发生错误: {e},跳过此页")
continue
# else:
# print(f"页面 {page_obj.page_number} 非横向,跳过此页")
if not valid_pages:
print(f"错误: 文件 '{pdf_path}' 未能找到任何有效的横向报关单页面。")
return []
# 动态查找包含基础信息的页面 (在有效页面列表中查找)
for idx, page_obj in enumerate(valid_pages):
try:
key_field_coord = (85.8, 75.4, 165.8, 84.5) # 预录入编号
if not (key_field_coord[0] < page_obj.width and key_field_coord[2] < page_obj.width and \
key_field_coord[1] < page_obj.height and key_field_coord[3] < page_obj.height):
continue
crop = page_obj.crop(key_field_coord)
text = crop.extract_text()
if text and text.strip() and len(text.strip()) > 3:
found_base_data_page_index_in_valid_pages = idx
print(f"找到基础信息页:有效页面列表中的第 {found_base_data_page_index_in_valid_pages + 1} 页 (物理页码 {page_obj.page_number})")
current_page_for_base_data = page_obj # 使用有效页面对象
page_width = current_page_for_base_data.width
page_height = current_page_for_base_data.height
field_coordinates = {
'预录入编号': (85.8, 75.4, 165.8, 84.5),
'海关编号': (295.2, 75.4, 375.8, 84.5),
'境内发货人': (36.75, 88.67, 255.375, 112.295),
'境外收货人': (36.75, 112.295, 255.375, 135.545),
'生产销售单位': (36.75, 135.545, 255.375, 158.795),
'运输方式': (255.375, 112.295, 383.625, 135.545),
'合同协议号': (36.75, 158.795, 255.375, 182.045),
'监管方式': (255.375, 135.545, 383.625, 158.795),
'征免性质': (383.625, 135.545, 516.375, 158.795),
'出口日期': (383.625, 88.67, 516.375, 112.295),
'运输工具名称及航次号': (383.625, 112.295, 516.375, 135.545),
'运抵国(地区)': (383.625, 158.795, 516.375, 182.045),
'包装种类': (36.75, 182.045, 255.375, 205.295),
'件数': (260.375, 182.045, 301.125, 205.295),
'毛重': (301.125, 182.045, 383.625, 205.295),
'净重': (383.625, 182.045, 463.125, 205.295),
'成交方式': (463.125, 182.045, 516.375, 205.295),
'离境口岸': (637.125, 158.795, 805.5, 182.045),
'许可证号': (516.375, 135.545, 805.5, 158.795),
'备案号': (637.125, 88.67, 805.5, 112.295),
'申报日期': (516.375, 88.67, 637.125, 112.295),
'指运港': (516.375, 158.795, 637.125, 182.045),
'提运单号': (516.375, 112.295, 805.5, 135.545),
'运费': (516.375, 182.045, 608.625, 205.295),
'保费': (608.625, 182.045, 700.875, 205.295),
'杂费': (700.875, 182.045, 805.5, 205.295),
'随附单证及编号': (36.75, 205.295, 805.5, 228.545),
'标记唛码及备注': (36.75, 228.545, 805.5, 274.295),
'申报单位': (78.8, 528.8, 294.8, 537.8)
}
for field, coords in field_coordinates.items():
x0, top, x1, bottom = coords
if not (x0 >= 0 and top >= 0 and x1 <= page_width and bottom <= page_height and x0 < x1 and top < bottom):
print(f"警告: 文件 '{pdf_path}',基础信息页 (物理页码 {current_page_for_base_data.page_number}),字段 '{field}' 的坐标 {coords} 无效或部分超出页面边界 ({page_width}, {page_height}),跳过此字段。")
continue
try:
crop_area = current_page_for_base_data.crop((x0, top, x1, bottom))
text_content = crop_area.extract_text(x_tolerance=1, y_tolerance=1)
if text_content:
# 初始清理:移除可能的字段名和前后空格
cleaned_text_intermediate = re.sub(rf'(?i)^{re.escape(field)}\s*:?\s*', '', text_content).strip()
# 如果第一次清理后结果为空,但原始文本不为空,说明可能字段名就是全部内容,或者清理过度
# 此时可以尝试使用原始文本,或者更保守的清理
if not cleaned_text_intermediate and text_content.strip():
# 尝试一个更简单的清理,只移除开头的字段名(不区分大小写)
cleaned_text_intermediate = re.sub(rf'(?i)^{re.escape(field)}', '', text_content).strip()
# 如果还是空,并且原始文本不等于字段名本身,则用原始文本
if not cleaned_text_intermediate and text_content.strip().lower() != field.lower():
cleaned_text_intermediate = text_content.strip()
elif not cleaned_text_intermediate and text_content.strip().lower() == field.lower():
# 如果清理后为空,且原始文本就是字段名,那么这个字段可能确实没有值
base_data_from_first_page[field] = '' # 或者 None,根据需求
continue
final_clean_text = cleaned_text_intermediate
# 提取括号内的代码
code_match = re.search(r'\(([^)]+)\)', final_clean_text)
if code_match:
code_value = code_match.group(1).strip()
# 提取代码后,从文本中移除括号及其内容,以及可能的尾随字段名
text_without_code = re.sub(r'\s*\(([^)]+)\)\s*', '', final_clean_text).strip()
# 再次尝试移除字段名,以防它在括号之后或之前
text_without_code_and_field = re.sub(rf'(?i)^{re.escape(field)}\s*:?\s*', '', text_without_code).strip()
if not text_without_code_and_field and text_without_code.strip(): # 如果移除字段名后空了,用没移除的
final_clean_text = text_without_code.strip()
else:
final_clean_text = text_without_code_and_field
if field == '境内发货人': base_data_from_first_page['境内发货人代码'] = code_value
elif field == '离境口岸': base_data_from_first_page['离境口岸代码'] = code_value
elif field == '监管方式': base_data_from_first_page['监管方式代码'] = code_value
elif field == '生产销售单位': base_data_from_first_page['生产销售单位代码'] = code_value
elif field == '指运港': base_data_from_first_page['指运港代码'] = code_value
elif field == '毛重': base_data_from_first_page['毛重代码'] = code_value
elif field == '净重': base_data_from_first_page['净重代码'] = code_value
elif field == '成交方式': base_data_from_first_page['成交方式代码'] = code_value
elif field == '申报单位': base_data_from_first_page['申报单位代码'] = code_value
elif field == '征免性质': base_data_from_first_page['征免性质代码'] = code_value
# 最后的清理,确保移除了字段名
final_value = re.sub(rf'(?i){re.escape(field)}\s*:?\s*', '', final_clean_text).strip()
final_value = re.sub(r'\s+', ' ', final_value).strip()
# 如果最终值不等于字段名本身(不区分大小写),则认为是有效值
if final_value.lower() != field.lower():
base_data_from_first_page[field] = final_value
elif base_data_from_first_page.get(field) is None: # 如果之前没有赋过值,且现在等于字段名,则赋空
base_data_from_first_page[field] = ''
except Exception as e:
print(f"警告: 文件 '{pdf_path}',基础信息页 (物理页码 {current_page_for_base_data.page_number}),字段 '{field}' 提取时发生错误: {e}。坐标: {coords}")
break
except Exception as e:
pass
if found_base_data_page_index_in_valid_pages == -1:
print(f"错误: 文件 '{pdf_path}' 在有效页面中未能找到任何包含基础信息的报关单页面。")
return []
# 处理商品项 (从有效页面列表中找到基础信息页开始的所有后续有效页)
collected_item_data_list = []
# 遍历有效页面列表,从基础信息页开始
for valid_page_idx in range(found_base_data_page_index_in_valid_pages, len(valid_pages)):
current_page_obj = valid_pages[valid_page_idx] # 使用有效页面对象
page_width = current_page_obj.width
page_height = current_page_obj.height
try:
current_page_row_coordinates = []
# 判断当前有效页面是否为基础信息页(即有效列表中的第一页)
if valid_page_idx == found_base_data_page_index_in_valid_pages:
current_page_row_coordinates = [
(36.75, 287.795, 805.5, 320.045), (36.75, 320.045, 805.5, 352.3),
(36.75, 352.3, 805.5, 384.55), (36.75, 384.55, 805.5, 416.8),
(36.75, 416.8, 805.5, 449.05), (36.75, 449.05, 805.5, 481.295)
]
else: # 适用于有效列表中的后续页的商品项坐标
current_page_row_coordinates = [
(36.75, 102.545, 805.5, 134.8), (36.75, 134.8, 805.5, 167.05),
(36.75, 167.05, 805.5, 199.3), (36.75, 199.3, 805.5, 231.55),
(36.75, 231.55, 805.5, 263.8), (36.75, 263.8, 805.5, 296.05),
(36.75, 296.05, 805.5, 328.3), (36.75, 328.3, 805.5, 360.55),
(36.75, 360.55, 805.5, 392.8), (36.75, 392.8, 805.5, 425.05),
(36.75, 425.05, 805.5, 457.3), (36.75, 457.3, 805.5, 489.55),
(36.75, 489.55, 805.5, 521.8), (36.75, 521.8, 805.5, 554.6075)
]
for item_row_idx, row_coords in enumerate(current_page_row_coordinates):
x0, top, x1, bottom = row_coords
if not (x0 >= 0 and top >= 0 and x1 <= page_width and bottom <= page_height and x0 < x1 and top < bottom):
print(f"警告: 文件 '{pdf_path}',有效页面 {valid_page_idx + 1} (物理页码 {current_page_obj.page_number}),商品行 {item_row_idx + 1} 的坐标 {row_coords} 无效,跳过此行。")
continue
item_data = {}
try:
crop_area = current_page_obj.crop((x0, top, x1, bottom))
full_text = crop_area.extract_text(x_tolerance=1, y_tolerance=1)
# 以下正则均为内容解析
if full_text and full_text.strip():
item_number_match = re.search(r'^\s*(\d{1,2})\s+', full_text)
if item_number_match: item_data['项号'] = int(item_number_match.group(1))
product_code_name_match = re.search(r'^\s*\d{1,2}\s+(\d+)([^\d\n]+)', full_text)
if product_code_name_match:
item_data['商品编号'] = product_code_name_match.group(1).strip()
item_data['商品名称'] = product_code_name_match.group(2).strip()
qty_unit_match = re.search(r'(\d+\.?\d*)(台|千克|个|件|套|箱)', full_text)
if qty_unit_match: item_data['数量及单位'] = qty_unit_match.group(0).strip()
product_match2 = re.findall(r'(?:\b\d+\|[^\s]*(?=\s+))|(?:\n\s*(?:[a-zA-Z]+|[\u4e00-\u9fa5]+|[a-zA-Z0-9]+/[a-zA-Z0-9]+|\d+[a-zA-Z]+/?[a-zA-Z/]*)(?=\s+))',full_text)
if product_match2: item_data['商品名称及规格型号'] = "".join(product_match2)
price_match = re.search(r'(\d+\.\d{4})', full_text)
if price_match: item_data['单价'] = price_match.group(1)
total_price_match = re.search(r'(\b\d+\.\d{2}\b)', full_text)
if total_price_match: item_data['总价'] = total_price_match.group(1)
currency_match = re.search(r'(美元|人民币|欧元|英镑|日元)', full_text)
if currency_match: item_data['币制'] = currency_match.group(1)
regex_pattern = r"芬兰|老挝|俄罗斯|白罗斯|乌克兰|摩尔达维亚|立陶宛|拉脱维亚|爱沙尼亚共和国|哈萨克斯坦|格鲁吉亚|乌兹别克斯坦|朝鲜|蒙古|越南|中国|波兰|保加利亚|捷克|匈牙利|斯洛伐克|阿塞拜疆|吉尔吉斯斯坦|塔吉克斯坦|土库曼斯坦|阿富汗|英国|西班牙|塞尔维亚|土耳其|德国|奥地利|卢森堡|意大利|荷兰|法国|比利时|伊朗|安道尔|阿联酋|安提瓜和巴布达|安圭拉|阿尔巴尼亚|亚美尼亚|安哥拉|南极洲|阿根廷|美属萨摩亚|澳大利亚|阿鲁巴|波黑|巴巴多斯|孟加拉|布基纳法索|巴林|布隆迪|贝宁|百慕大|文莱|玻利维亚|荷兰加勒比区|巴西|巴哈马|不丹|博茨瓦纳|伯利兹|加拿大|刚果(金)|中非|刚果(布)|瑞士|科特迪瓦|智利|喀麦隆|哥伦比亚|哥斯达黎加|古巴|佛得角|塞浦路斯|吉布提|丹麦|多米尼克|多米尼加|阿尔及利亚|厄瓜多尔|爱沙尼亚|埃及|西撒哈拉|厄立特里亚|埃塞俄比亚|密克罗尼西亚联邦|加蓬|格林纳达|法属圭亚那|加纳|直布罗陀|格陵兰|冈比亚|几内亚|瓜德罗普|赤道几内亚|希腊|危地马拉|几内亚比绍|圭亚那|洪都拉斯|克罗地亚|海地|印尼|印度尼西亚共和国|爱尔兰|以色列|印度|英属印度洋领地|伊拉克|牙买加|约旦|日本|肯尼亚|柬埔寨|基里巴斯|科摩罗|圣基茨和尼维斯|韩国|科威特|黎巴嫩|圣卢西亚|列支敦士登|斯里兰卡|利比里亚|莱索托|利比亚|摩洛哥|摩纳哥|黑山|法属圣马丁|马达加斯加|马其顿|马里|缅甸|马提尼克|毛里塔尼亚|马耳他|毛里求斯|马尔代夫|马拉维|墨西哥|马来西亚|莫桑比克|纳米比亚|新喀里多尼亚|尼日尔|尼日利亚|尼加拉瓜|挪威|尼泊尔|瑙鲁|纽埃|新西兰|阿曼|巴拿马|秘鲁|法属波利尼西亚|巴布亚新几内亚|菲律宾|巴基斯坦|圣皮埃尔和密克隆|波多黎各|巴勒斯坦|葡萄牙|帕劳|巴拉圭|卡塔尔|留尼汪|罗马尼亚|卢旺达|沙特阿拉伯|塞舌尔|苏丹|瑞典|新加坡|圣赫勒拿|斯洛文尼亚|塞拉利昂|圣马力诺|塞内加尔|索马里|苏里南|南苏丹|圣多美和普林西比|萨尔瓦多|叙利亚|斯威士兰|乍得|法属南部领地|多哥|泰国|托克劳|东帝汶|突尼斯|汤加|特立尼达和多巴哥|图瓦卢|坦桑尼亚|乌干达|美国|乌拉圭|梵蒂冈|圣文森特和格林纳丁斯|委内瑞拉|瓦努阿图|瓦利斯和富图纳|萨摩亚|也门|马约特|南非|赞比亚|津巴布韦"
country_names = re.findall(regex_pattern, full_text)
if len(country_names) >= 2:
item_data['原产国'] = country_names[0]
item_data['最终目的国'] = country_names[1]
source_match = re.search(r'\((\d{5})\)\s*([^()]+?)(?=\s*(?:照章征税|\(CHN\)))', full_text)
if source_match: item_data['境内货源地'] = source_match.group(1) + source_match.group(2).strip()
tax_match = re.search(r'(照章征税|免税|保税|减免|先征后退|先征后返|保证金|暂定税率|特惠税率|最惠国税率|普通税率|协定税率)',full_text)
if tax_match: item_data['征免性质'] = tax_match.group(1)
declare_match = re.search(r'申报单位[\s::]*\(.*?\)(.*?)',full_text)
if declare_match: item_data['申报单位'] = declare_match.group(1)
if '商品编号' in item_data and item_data['商品编号'] and '商品名称' in item_data and item_data['商品名称']:
collected_item_data_list.append(item_data)
except Exception as e:
print(f"警告: 文件 '{pdf_path}',有效页面 {valid_page_idx + 1} (物理页码 {current_page_obj.page_number}),商品行 {item_row_idx + 1} 提取时发生错误: {e}。坐标: {row_coords}")
except Exception as e:
print(f"处理文件 '{pdf_path}' 的有效页面 {valid_page_idx + 1} (物理页码 {current_page_obj.page_number}) 商品项时发生错误: {e}")
# 将基础数据与每个商品项数据合并
if collected_item_data_list:
for item_data in collected_item_data_list:
# 创建一个新的字典,先复制基础信息,然后更新商品项特有信息
final_item_data = base_data_from_first_page.copy()
final_item_data.update(item_data)
all_data.append(final_item_data)
elif not base_data_from_first_page and not collected_item_data_list:
print(f"警告: 文件 '{pdf_path}' 未能提取到任何基础信息或商品项信息。")
return []
elif base_data_from_first_page and not collected_item_data_list: # 只有基础信息
all_data.append(base_data_from_first_page.copy())
if all_data:
all_data.sort(key=lambda x: (x.get('文件名', ''), x.get('项号', float('inf'))))
current_item_number = 1
for item in all_data:
if '商品编号' in item and item['商品编号']:
item['项号'] = current_item_number
current_item_number += 1
# else: item['项号'] = None # 对于只有基础信息的条目,项号可以保持为None
return all_data
except Exception as e:
print(f"提取数据过程中发生严重错误: {e}")
import traceback
traceback.print_exc() # 打印完整的错误堆栈信息
return []
def extract_text_by_position(page, x0, top, x1, bottom):
"""从指定坐标区域提取文本"""
try:
crop = page.crop((x0, top, x1, bottom))
return crop.extract_text()
except Exception as e:
print(f"提取文本时出错: {e}")
return ""
def save_to_mysql(data, table_name="te_bgd"):
"""将数据保存到MySQL数据库"""
connection = None # 初始化connection为None
try:
# 建立连接
connection = pymysql.connect(
host='****.mysql.rds.aliyuncs.com',
port=3306,
user='teuser',
password='*****',
database='tjtedb',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
print("数据库连接成功") # 新增,确认连接成功
with connection.cursor() as cursor:
# 准备批量插入的数据
insert_data = []
for item in data:
# 创建一个元组,包含要插入的字段值
row_data = (
item.get('文件名', ''),
item.get('预录入编号', ''),
item.get('海关编号', ''),
item.get('境内发货人代码', ''),
item.get('境内发货人', ''),
item.get('离境口岸代码', ''),
item.get('离境口岸', ''),
item.get('申报日期', ''),
item.get('境外收货人', ''),
item.get('运输方式', ''),
item.get('运输工具名称及航次号', ''),
item.get('提运单号', ''),
item.get('生产销售单位代码', ''),
item.get('生产销售单位', ''),
item.get('监管方式代码', ''),
item.get('监管方式', ''),
item.get('合同协议号', ''),
item.get('贸易国(地区)', ''),
item.get('运抵国(地区)', ''),
item.get('指运港代码', ''),
item.get('指运港', ''),
item.get('离境口岸代码', ''),
item.get('离境口岸', ''),
item.get('包装种类', ''),
item.get('件数', ''),
item.get('毛重代码', ''),
item.get('毛重', ''),
item.get('净重代码', ''),
item.get('净重', ''),
item.get('成交方式代码', ''),
item.get('成交方式', ''),
item.get('随附单证及编号', ''),
item.get('标记唛码及备注', ''),
item.get('申报单位代码', ''),
item.get('申报单位', ''),
item.get('项号', ''),
item.get('商品编号', ''),
item.get('商品名称', ''),
item.get('商品名称及规格型号', ''),
item.get('数量及单位', ''),
item.get('单价', ''),
item.get('总价', ''),
item.get('币制', ''),
item.get('原产国', ''),
item.get('最终目的国', ''),
item.get('境内货源地', ''),
item.get('征免性质代码', ''),
item.get('征免性质', ''),
item.get('运费', ''),
item.get('保费', ''),
item.get('杂费', '')
)
insert_data.append(row_data)
# 构建SQL插入语句
fields = [
"file_name", "pre_input_number", "customs_number", "domestic_shipper_code",
"domestic_shipper", "exit_customs_code", "exit_customs", "date_of_declaration",
"overseas_consignee", "mode_of_transport", "transport_vehicle_name_and_voyage_number",
"delivery_numbers", "production_and_sales_unit_code", "production_and_sales_units",
"regulatory_code", "regulatory_approach", "contract_number", "trading_country_region",
"destination_country_region", "designated_port_code", "port_of_destination",
"departure_port_code", "port_of_departure", "packaging_type", "quantity",
"gross_weight_code", "gross_weight", "net_weight_code", "net_weight", "transaction_method_code",
"transaction_method", "accompanying_documents_and_numbers", "shipping_marks_remarks",
"declaration_unit_code", "declaration_unit", "item_number", "product_code",
"product_name", "product_name_and_specification_model", "quantity_and_unit",
"unit_price", "total_price", "currency_system", "country_of_origin",
"final_destination_country", "original_place_of_delivered_goods", "exemption_nature_code",
"nature_of_exemption","shipping_fee","premium","miscellaneous_expenses"
]
if not insert_data: # 如果没有数据可以插入
print("没有数据需要插入数据库。")
return True # 或者 False
# 确保字段数量与值数量匹配 (仅在有数据时检查第一条)
if len(fields) != len(insert_data[0]):
print(f"错误:字段数量({len(fields)})与值数量({len(insert_data[0])})不匹配")
print(f"字段列表: {fields}")
print(f"第一行数据: {insert_data[0]}")
return False
sql = """
INSERT INTO {} ({}) VALUES ({})
""".format(
table_name,
", ".join(fields),
", ".join(['%s'] * len(fields))
)
cursor.executemany(sql, insert_data)
connection.commit()
print(f"成功将 {len(insert_data)} 条数据插入到数据库表 {table_name}")
return True
except Exception as e:
print(f"保存到数据库时出错: {e}")
if connection:
connection.rollback()
return False
finally:
if connection:
connection.close()
print("数据库连接已关闭")
def save_to_excel(data, output_path):
"""将数据保存到Excel文件,这个现在不需要了"""
try:
df = pd.DataFrame(data)
df.to_excel(output_path, index=False)
print(f"数据已保存到 {output_path}")
return True
except Exception as e:
print(f"保存Excel时出错: {e}")
return False
def process_pdf_files(pdf_path):
"""处理指定的PDF文件并将结果保存到数据库"""
all_pdf_data = []
data = extract_data_from_pdf_by_position(pdf_path)
if data:
all_pdf_data.extend(data)
print(f"从 {os.path.basename(pdf_path)} 提取了 {len(data)} 条数据")
else:
print(f"无法从 {os.path.basename(pdf_path)} 提取数据")
return 3 # 无法提取数据
if all_pdf_data:
res = save_to_mysql(all_pdf_data)
if res:
print("数据成功保存到数据库")
return 0 # 保存成功
else:
print("数据保存到数据库失败")
return 4 # 保存失败
else:
# 这个分支理论上在上面 data 为空时已经返回了,但为了逻辑完整性保留
print("没有从任何PDF文件中提取到数据")
return 3 # 无法提取数据
def isPdf(file_path):
try:
with open(file_path, 'rb') as f:
header = f.read(5)
return header == b'%PDF-'
except:
return False
if __name__ == "__main__":
print("程序开始执行...")
if len(sys.argv) != 2:
print("参数错误:需要提供一个文件夹路径")
sys.exit(1)
folderPath = sys.argv[1]
print(f"接收到的文件夹路径: {folderPath}")
if not os.path.isdir(folderPath):
print(f"路径错误:'{folderPath}' 不是一个有效的文件夹")
sys.exit(1)
pdf_files_processed_count = 0
pdf_files_failed_count = 0
for root, dirs, files in os.walk(folderPath):
for file in files:
if file.lower().endswith('.pdf'):
filePath = os.path.join(root, file)
print(f"\n开始处理PDF文件: {filePath}")
if not isPdf(filePath):
print(f"文件类型错误:'{filePath}' 不是一个有效的PDF文件,跳过")
pdf_files_failed_count += 1
continue
exit_code = process_pdf_files(filePath)
if exit_code == 0:
pdf_files_processed_count += 1
print(f"文件 {filePath} 处理成功。")
else:
pdf_files_failed_count += 1
print(f"文件 {filePath} 处理失败,退出码: {exit_code}")
print("暂停1秒...")
time.sleep(1) # 每处理完一个PDF后暂停1秒
print(f"\n所有PDF文件处理完成。")
print(f"成功处理文件数: {pdf_files_processed_count}")
print(f"处理失败文件数: {pdf_files_failed_count}")
sys.exit(0) # 所有文件处理完毕后以成功状态退出
print(f"PDF文件处理完成,退出码: {exit_code}")
sys.exit(exit_code)
本文作者:ivan
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!