base_country_code.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. import os
  2. import re
  3. from pathlib import Path
  4. import pandas as pd
  5. from openpyxl import load_workbook
  6. YEAR_PATTERN = re.compile(r"^\d{4}$")
  7. MONTH_PATTERN = re.compile(r"^(0[1-9]|1[0-2])$")
  8. def format_sql_value(value):
  9. """
  10. 将 Python 值转换为 SQL 可识别的格式:
  11. - None -> NULL
  12. - 数值 -> 原样输出
  13. - 字符串 -> 加单引号
  14. """
  15. if pd.isna(value):
  16. return 'NULL'
  17. elif isinstance(value, (int, float)):
  18. return str(value)
  19. else:
  20. return f"'{value}'"
  21. def find_sheet_by_keyword(file_path, keyword):
  22. """
  23. 模糊查找包含关键字的 sheet 名称(支持 .xls 和 .xlsx)
  24. :param file_path: Excel 文件路径
  25. :param keyword: 要匹配的关键字(如 '类章')
  26. :return: 匹配到的第一个 sheet 名称,或 None
  27. """
  28. # 处理 .xlsx 文件
  29. if file_path.suffix == ".xlsx":
  30. workbook = load_workbook(filename=file_path, read_only=True)
  31. sheets = workbook.sheetnames
  32. # 处理 .xls 文件
  33. elif file_path.suffix == ".xls":
  34. import xlrd
  35. workbook = xlrd.open_workbook(file_path)
  36. sheets = workbook.sheet_names()
  37. else:
  38. raise ValueError(f"不支持的文件格式:{file_path.suffix}")
  39. # 精确匹配 + 模糊匹配策略
  40. for sheet in sheets:
  41. if keyword.lower() in sheet.lower():
  42. return sheet
  43. return None
  44. def get_previous_month_dir(current_path):
  45. """生成前月目录路径"""
  46. try:
  47. year_part = current_path.parent.name
  48. month_part = current_path.name
  49. if not (YEAR_PATTERN.match(year_part) and MONTH_PATTERN.match(month_part)):
  50. return None
  51. prev_month = int(month_part) - 1
  52. if prev_month < 1:
  53. return None
  54. return current_path.parent.parent / current_path.parent.name / f"{prev_month:02d}"
  55. except Exception as e:
  56. print(f"前月目录生成失败:{str(e)}")
  57. return None
  58. COUNTRY_CODE_MAPPING = {
  59. # ================= 亚洲 =================
  60. "阿富汗": "AF",
  61. "巴林": "BH",
  62. "孟加拉国": "BD",
  63. "不丹": "BT",
  64. "文莱": "BN",
  65. "缅甸": "MM",
  66. "柬埔寨": "KH",
  67. "塞浦路斯": "CY",
  68. "朝鲜": "KP",
  69. "中国香港": "HK",
  70. "印度": "IN",
  71. "印度尼西亚": "ID",
  72. "伊朗": "IR",
  73. "伊拉克": "IQ",
  74. "以色列": "IL",
  75. "日本": "JP",
  76. "约旦": "JO",
  77. "科威特": "KW",
  78. "老挝": "LA",
  79. "黎巴嫩": "LB",
  80. "中国澳门": "MO",
  81. "马来西亚": "MY",
  82. "马尔代夫": "MV",
  83. "蒙古": "MN",
  84. "尼泊尔": "NP",
  85. "阿曼": "OM",
  86. "巴基斯坦": "PK",
  87. "巴勒斯坦": "PS",
  88. "菲律宾": "PH",
  89. "卡塔尔": "QA",
  90. "沙特阿拉伯": "SA",
  91. "新加坡": "SG",
  92. "韩国": "KR",
  93. "斯里兰卡": "LK",
  94. "叙利亚": "SY",
  95. "泰国": "TH",
  96. "土耳其": "TR",
  97. "阿联酋": "AE",
  98. "也门": "YE",
  99. "越南": "VN",
  100. "中国": "CN",
  101. "中国台湾": "TW",
  102. "哈萨克斯坦": "KZ",
  103. "吉尔吉斯斯坦": "KG",
  104. "塔吉克斯坦": "TJ",
  105. "土库曼斯坦": "TM",
  106. "乌兹别克斯坦": "UZ",
  107. "格鲁吉亚": "GE",
  108. "亚美尼亚": "AM",
  109. "阿塞拜疆": "AZ",
  110. # ================= 非洲 =================
  111. "阿尔及利亚": "DZ",
  112. "安哥拉": "AO",
  113. "贝宁": "BJ",
  114. "博茨瓦纳": "BW",
  115. "布隆迪": "BI",
  116. "喀麦隆": "CM",
  117. "佛得角": "CV",
  118. "中非": "CF",
  119. "乍得": "TD",
  120. "科摩罗": "KM",
  121. "刚果共和国": "CG",
  122. "吉布提": "DJ",
  123. "埃及": "EG",
  124. "赤道几内亚": "GQ",
  125. "埃塞俄比亚": "ET",
  126. "加蓬": "GA",
  127. "冈比亚": "GM",
  128. "加纳": "GH",
  129. "几内亚": "GN",
  130. "几内亚比绍": "GW",
  131. "科特迪瓦": "CI",
  132. "肯尼亚": "KE",
  133. "莱索托": "LS",
  134. "利比里亚": "LR",
  135. "利比亚": "LY",
  136. "马达加斯加": "MG",
  137. "马拉维": "MW",
  138. "马里": "ML",
  139. "毛里塔尼亚": "MR",
  140. "毛里求斯": "MU",
  141. "摩洛哥": "MA",
  142. "莫桑比克": "MZ",
  143. "纳米比亚": "NA",
  144. "尼日尔": "NE",
  145. "尼日利亚": "NG",
  146. "卢旺达": "RW",
  147. "圣多美和普林西比": "ST",
  148. "塞内加尔": "SN",
  149. "塞舌尔": "SC",
  150. "塞拉利昂": "SL",
  151. "索马里": "SO",
  152. "南非": "ZA",
  153. "苏丹": "SD",
  154. "坦桑尼亚": "TZ",
  155. "多哥": "TG",
  156. "突尼斯": "TN",
  157. "乌干达": "UG",
  158. "布基纳法索": "BF",
  159. "刚果民主共和国": "CD",
  160. "赞比亚": "ZM",
  161. "津巴布韦": "ZW",
  162. "厄立特里亚": "ER",
  163. "南苏丹": "SS",
  164. # ================= 欧洲 =================
  165. "比利时": "BE",
  166. "丹麦": "DK",
  167. "英国": "GB",
  168. "德国": "DE",
  169. "法国": "FR",
  170. "爱尔兰": "IE",
  171. "意大利": "IT",
  172. "卢森堡": "LU",
  173. "荷兰": "NL",
  174. "希腊": "GR",
  175. "葡萄牙": "PT",
  176. "西班牙": "ES",
  177. "阿尔巴尼亚": "AL",
  178. "奥地利": "AT",
  179. "保加利亚": "BG",
  180. "芬兰": "FI",
  181. "匈牙利": "HU",
  182. "冰岛": "IS",
  183. "列支敦士登": "LI",
  184. "马耳他": "MT",
  185. "挪威": "NO",
  186. "波兰": "PL",
  187. "罗马尼亚": "RO",
  188. "瑞典": "SE",
  189. "瑞士": "CH",
  190. "爱沙尼亚": "EE",
  191. "拉脱维亚": "LV",
  192. "立陶宛": "LT",
  193. "白俄罗斯": "BY",
  194. "摩尔多瓦": "MD",
  195. "俄罗斯": "RU",
  196. "乌克兰": "UA",
  197. "斯洛文尼亚": "SI",
  198. "克罗地亚": "HR",
  199. "捷克": "CZ",
  200. "斯洛伐克": "SK",
  201. "北马其顿": "MK",
  202. "波斯尼亚和黑塞哥维那": "BA",
  203. "梵蒂冈": "VA",
  204. "塞尔维亚": "RS",
  205. "黑山": "ME",
  206. # ================= 美洲 =================
  207. "安提瓜和巴布达": "AG",
  208. "阿根廷": "AR",
  209. "巴哈马": "BS",
  210. "巴巴多斯": "BB",
  211. "伯利兹": "BZ",
  212. "玻利维亚": "BO",
  213. "巴西": "BR",
  214. "加拿大": "CA",
  215. "智利": "CL",
  216. "哥伦比亚": "CO",
  217. "哥斯达黎加": "CR",
  218. "古巴": "CU",
  219. "多米尼克": "DM",
  220. "多米尼加": "DO",
  221. "厄瓜多尔": "EC",
  222. "萨尔瓦多": "SV",
  223. "格林纳达": "GD",
  224. "危地马拉": "GT",
  225. "圭亚那": "GY",
  226. "海地": "HT",
  227. "洪都拉斯": "HN",
  228. "牙买加": "JM",
  229. "墨西哥": "MX",
  230. "尼加拉瓜": "NI",
  231. "巴拿马": "PA",
  232. "巴拉圭": "PY",
  233. "秘鲁": "PE",
  234. "圣卢西亚": "LC",
  235. "圣文森特和格林纳丁斯": "VC",
  236. "苏里南": "SR",
  237. "特立尼达和多巴哥": "TT",
  238. "美国": "US",
  239. "乌拉圭": "UY",
  240. "委内瑞拉": "VE",
  241. "圣基茨和尼维斯": "KN",
  242. # ================= 大洋洲 =================
  243. "澳大利亚": "AU",
  244. "斐济": "FJ",
  245. "基里巴斯": "KI",
  246. "马绍尔群岛": "MH",
  247. "密克罗尼西亚联邦": "FM",
  248. "瑙鲁": "NR",
  249. "新西兰": "NZ",
  250. "帕劳": "PW",
  251. "巴布亚新几内亚": "PG",
  252. "萨摩亚": "WS",
  253. "所罗门群岛": "SB",
  254. "汤加": "TO",
  255. "图瓦卢": "TV",
  256. "瓦努阿图": "VU",
  257. # ================= 特殊地区 =================
  258. "法属圭亚那": "GF",
  259. "瓜德罗普": "GP",
  260. "留尼汪": "RE",
  261. "圣马丁": "MF",
  262. "荷属圣马丁": "SX",
  263. "法属波利尼西亚": "PF",
  264. "新喀里多尼亚": "NC",
  265. "库克群岛": "CK",
  266. "关岛": "GU",
  267. "波多黎各": "PR",
  268. "美属萨摩亚": "AS",
  269. "百慕大": "BM",
  270. "开曼群岛": "KY",
  271. "福克兰群岛(马尔维纳斯)": "FK",
  272. "格陵兰": "GL",
  273. "法属南方领地": "TF",
  274. "赫德岛和麦克唐纳岛": "HM",
  275. "托克劳": "TK",
  276. "纽埃": "NU",
  277. "诺福克岛": "NF",
  278. "北马里亚纳群岛": "MP",
  279. "皮特凯恩": "PN",
  280. "圣赫勒拿": "SH",
  281. "斯瓦尔巴群岛和扬马延岛": "SJ",
  282. "东帝汶": "TL",
  283. # ==== 欧洲特殊地区 ====
  284. "加那利群岛": "IC", # 西班牙特殊领土代码
  285. "塞卜泰(休达)": "XC", # 休达官方代码
  286. "梅利利亚": "XL", # 梅利利亚官方代码
  287. "安道尔": "AD",
  288. "直布罗陀": "GI",
  289. "摩纳哥": "MC",
  290. "圣马力诺": "SM",
  291. "法罗群岛": "FO", # 丹麦自治领
  292. "奥兰群岛": "AX", # 芬兰自治省
  293. "格恩西": "GG", # 英国皇家属地
  294. "马恩岛": "IM",
  295. "泽西": "JE",
  296. # ==== 非洲特殊地区 ====
  297. "西撒哈拉": "EH", # 争议地区代码
  298. "斯威士兰": "SZ", # 正式国名为"Eswatini"但保留旧映射
  299. "马约特": "YT", # 法国海外省
  300. # ==== 美洲特殊地区 ====
  301. "英属印度洋领地": "IO",
  302. "阿鲁巴": "AW",
  303. "库拉索": "CW",
  304. "马提尼克": "MQ", # 法国海外省
  305. "蒙特塞拉特": "MS",
  306. "法属圣马丁": "MF",
  307. "特克斯和凯科斯群岛": "TC",
  308. "英属维尔京群岛": "VG",
  309. "博纳尔,圣俄斯塔休斯和萨巴": "BQ",
  310. "圣巴泰勒米": "BL", # 法国海外集体
  311. "美属维尔京群岛": "VI",
  312. "安圭拉": "AI",
  313. "圣皮埃尔和密克隆": "PM",
  314. # ==== 大洋洲特殊地区 ====
  315. "瓦利斯和富图纳": "WF",
  316. "科科斯(基林)群岛": "CC",
  317. "圣诞岛": "CX",
  318. "美国本土外小岛屿": "UM",
  319. # ==== 特殊标记 ====
  320. "布维岛": "BV", # 挪威属地
  321. "南乔治亚岛和南桑德韦奇岛": "GS",
  322. "国家(地区)不明": "XX" # 自定义代码
  323. }
  324. def extract_year_month_from_path(path):
  325. parts = path.parts
  326. try:
  327. year_part = parts[-2]
  328. month_part = parts[-1]
  329. if not YEAR_PATTERN.match(year_part):
  330. raise ValueError(f"无效年份格式:{year_part}")
  331. if not MONTH_PATTERN.match(month_part):
  332. raise ValueError(f"无效月份格式:{month_part}")
  333. return int(year_part), int(month_part)
  334. except IndexError:
  335. raise ValueError("路径结构不符合要求,示例:.../shandong/2025/04")
  336. download_dir = os.path.abspath(os.path.join('downloads'))
  337. download_dir_find = os.path.abspath(os.path.join('downloads/demo'))
  338. if __name__ == '__main__':
  339. year, month = extract_year_month_from_path(Path(download_dir)/'2025'/'02')
  340. print(year, month)