From 7883a2d349e3c47618133b687e4eccbcb9e7c39b Mon Sep 17 00:00:00 2001 From: zhaoxiangpeng <1943364377@qq.com> Date: Mon, 12 Jan 2026 17:38:55 +0800 Subject: [PATCH] =?UTF-8?q?cnki:=E5=85=AC=E5=85=B1=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/extract_rule.py | 15 + .../science_article_cnki/utils/logformat.py | 8 + .../science_article_cnki/utils/ti_match_id.py | 409 ++++++++++++++++++ .../science_article_cnki/utils/tools.py | 271 +++++++++++- 4 files changed, 699 insertions(+), 4 deletions(-) create mode 100644 science_article_cnki/science_article_cnki/utils/extract_rule.py create mode 100644 science_article_cnki/science_article_cnki/utils/logformat.py create mode 100644 science_article_cnki/science_article_cnki/utils/ti_match_id.py diff --git a/science_article_cnki/science_article_cnki/utils/extract_rule.py b/science_article_cnki/science_article_cnki/utils/extract_rule.py new file mode 100644 index 0000000..d402f06 --- /dev/null +++ b/science_article_cnki/science_article_cnki/utils/extract_rule.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/5/13 16:53 +# @Author : zhaoxiangpeng +# @File : extract_rule.py + +# 提取ISSN号 +ISSN_REGEX_PATTERN = r'ISSN:(\d{4}-[\dX]{4})' +# 提取CN号, https://baike.baidu.com/item/%E5%9B%BD%E5%86%85%E7%BB%9F%E4%B8%80%E5%88%8A%E5%8F%B7/386463 +CN_REGEX_PATTERN = r'CN:(\d{2}-\d{4}/?[A-Z]?)' + +# 去除/替换标题中的特殊字符 +DEL_TITLE_SYMBOL_PATTERN = '[’!"#$%&\'()*+,-.·/::;<=>—?@,。?★、…()【】《》?“”‘’![\\]^_`{|}~\s]+' + +# 去除特殊字符后的字符 +DEL_SOURCE_SYMBOL_PATTERN = DEL_TITLE_SYMBOL_PATTERN diff --git a/science_article_cnki/science_article_cnki/utils/logformat.py b/science_article_cnki/science_article_cnki/utils/logformat.py new file mode 100644 index 0000000..5d063d6 --- /dev/null +++ b/science_article_cnki/science_article_cnki/utils/logformat.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# @Time : 2026/1/12 14:31 +# @Author : zhaoxiangpeng +# @File : logformat.py + + +def pformat_dict(**kwargs): + return ', '.join([f'{k}={v}' for k, v in kwargs.items()]) diff --git a/science_article_cnki/science_article_cnki/utils/ti_match_id.py b/science_article_cnki/science_article_cnki/utils/ti_match_id.py new file mode 100644 index 0000000..cdde1de --- /dev/null +++ b/science_article_cnki/science_article_cnki/utils/ti_match_id.py @@ -0,0 +1,409 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/5/23 16:22 +# @Author : zhaoxiangpeng +# @File : ti_match_id.py + +from .tools import ji2format, ti2format + +TYPE1 = '1@' +TYPE2 = '2@' +TAG_TYPE_LENGTH = 2 +GET_TYPE_MAP = {TYPE1, TYPE2} + + +def ti2unique(ti=None, ji=None, y=None, i=None): + """ + 标题加其他标志作为唯一号 + :param ti: + :param ji: 期刊issn + :param y: + :param i: + :return: + """ + if ji: + ji = ji2format(ji) + ti_unique = '{ti}:{j}:{y}{i}'.format(ti=ti, j=ji, y=y, i=i) + return ti_unique + + +def ti2unique_type1(ti=None, ji=None, y=None, i=None): + """ + 标题加其他标志作为唯一号 + :param ti: + :param ji: 期刊issn + :param y: + :param i: + :return: + """ + if ji: + ji = ji2format(ji) + ti_unique = TYPE1 + '{ti}:{j}:{y}{i}'.format(ti=ti, j=ji, y=y, i=i) + return ti_unique + + +def ti2unique_type2(ti=None, so=None): + """ + 生成检索结果的唯一id + :param ti: + :param so: + :return: + """ + if so: + so = ti2format(so) + ti_unique = TYPE2 + '{ti}:{so}'.format(ti=ti, so=so) + return ti_unique + + +class TitleMatchIdTool: + def __init__(self, id_ti_info: str = None): + self._id_ti_info = id_ti_info + self._map_count = 0 + # self._unfold_map = self.make_ti_id_relation(id_ti_info) + self._unfold_map_extend = self.ti_id_relation(id_ti_info) + + def make_ti_id_relation(self, ti_map_str: str) -> dict: + """ + 展开字符串关系 + :return: + """ + result = {} + count = 0 + del_top_id_set = set() + del_top_issue = {} + del_issn_id_coll = {} + del_issue_coll = {} + id_ti_list = ti_map_str.split(';') + for s in id_ti_list: + count += 1 + i, ti = s.split(',') + # 标题可能会重复,那么标题需要时一对多 + # 预处理标题 + ti_format, is_format, issue_format = ti.split(':') + if not result.get(ti_format): + result.setdefault(ti_format, {}) + else: + del_top_id_set.add(ti_format) + # 需要先把标题的字典里有一个id字段 + if not result[ti_format].get('id'): + result[ti_format].setdefault('id', i) + else: + # 设置过id说明标题有重复,就要删除掉id字段,进行下层处理 + del_top_id_set.add(ti_format) + # 再加一层结构 + if not result[ti_format].get(is_format): + result[ti_format].setdefault(is_format, {}) + # 在issn层中设置id + result[ti_format][is_format].setdefault('id', i) + else: + # 说明issn有重复,删除掉id + del_issn_id_coll.setdefault(ti_format, []).append(is_format) + # 在issn层中设置期关联id + if not result[ti_format][is_format].get(issue_format): + result[ti_format][is_format].setdefault(issue_format, i) + # 在标题层设置期关联id + if not result[ti_format].get(issue_format): + result[ti_format].setdefault(issue_format, i) + else: + del_top_issue.setdefault('issue', []).append(issue_format) + else: + # 说明同一本期刊的期也重复了,那么重复的期数都不可信 + del_issue_coll.setdefault(ti_format, {}).setdefault(is_format, []).append(issue_format) + count -= 1 + if del_top_id_set: + for del_top in del_top_id_set: + result[del_top].pop('id', None) + if del_issn_id_coll: + for key_ti, vals in del_issn_id_coll.items(): + for val in vals: + result[key_ti][val].pop('id', None) + # 删除期重复的 + if del_issue_coll: + for key_ti, is_info in del_issue_coll.items(): + for ii in is_info: + for x in is_info[ii]: + count -= 1 + # 移除issn中的的期 + result[key_ti][ii].pop(x, None) + # 移除最上层的期 + result[key_ti].pop(x, None) + self._map_count = count + return result + + def get_id_use_ti_unique(self, ti_unique: str): + """ + 使用格式化标题匹配id + :param ti_unique: + :return: + """ + unfold_map = self._unfold_map_extend.get(TYPE1) + if not unfold_map: + return None + + ti_format, is_format, issue_format = ti_unique.split(':') + obj = unfold_map.get(ti_format) + if not obj: + return None + # 直接获取id key,如果可以获取到,说明只有一个没有重复,直接返回 + t_id = obj.get('id') + if t_id: + return t_id + # 没有获取到走issn的逻辑,issn可能会因为过刊的原因变化 + is_obj = obj.get(is_format) # 获取到issn层的对象 + if not is_obj: + return None + # 如果获取到,那么唯一 + t_id = is_obj.get('id') + if t_id: + return t_id + # 获取不到可能不唯一,进行期获取 + t_id = is_obj.get(issue_format) + if t_id: + return t_id + # 以上流程走完如果还没有匹配到,那么直接通过标题和期进行匹配 + issue_t_id = obj.get(issue_format, None) + # 如果依然获取不到,返回 None,流程结束 + return issue_t_id + + def get_id_use_ti_unique2(self, ti_unique: str): + """ + 使用格式化标题匹配id + :param ti_unique: + :return: + """ + unfold_map = self._unfold_map_extend.get(TYPE2) + if not unfold_map: + return None + + ti_format, so_format = ti_unique.split(':') + obj = unfold_map.get(ti_format) + if not obj: + return None + # 直接获取id key,如果可以获取到,说明只有一个没有重复,直接返回 + t_id = obj.get('id') + if t_id: + return t_id + # 没有获取到走期刊名称的逻辑 + is_obj = obj.get(so_format) # 获取到issn层的对象 + if not is_obj: + return None + + def get_id_control(self, ti_unique: str): + type_ = ti_unique[:TAG_TYPE_LENGTH] + if type_ not in GET_TYPE_MAP: + type_ = TYPE1 + ti2uni = ti_unique + else: + ti2uni = ti_unique[TAG_TYPE_LENGTH:] + func = {TYPE1: self.get_id_use_ti_unique, TYPE2: self.get_id_use_ti_unique2} + return func[type_](ti2uni) + + def count(self): + return self._map_count + + @staticmethod + def format_article_title(title: str) -> str: + """ + 去除特殊字符 + :param title: + :return: + """ + + @staticmethod + def format_journal_issn(issn: str) -> str: + """ + 去除特殊字符 + :param issn: + :return: + """ + + def make_ti_id_type1(self, datas): + result = {} + count = 0 + del_top_id_set = set() + del_top_issue = {} + del_issn_id_coll = {} + del_issue_coll = {} + for s in datas: + count += 1 + i, ti = s + # 标题可能会重复,那么标题需要时一对多 + # 预处理标题 + ti_format, is_format, issue_format = ti.split(':') + if not result.get(ti_format): + result.setdefault(ti_format, {}) + else: + del_top_id_set.add(ti_format) + # 需要先把标题的字典里有一个id字段 + if not result[ti_format].get('id'): + result[ti_format].setdefault('id', i) + else: + # 设置过id说明标题有重复,就要删除掉id字段,进行下层处理 + del_top_id_set.add(ti_format) + # 再加一层结构 + if not result[ti_format].get(is_format): + result[ti_format].setdefault(is_format, {}) + # 在issn层中设置id + result[ti_format][is_format].setdefault('id', i) + else: + # 说明issn有重复,删除掉id + del_issn_id_coll.setdefault(ti_format, []).append(is_format) + # 在issn层中设置期关联id + if not result[ti_format][is_format].get(issue_format): + result[ti_format][is_format].setdefault(issue_format, i) + # 在标题层设置期关联id + if not result[ti_format].get(issue_format): + result[ti_format].setdefault(issue_format, i) + else: + del_top_issue.setdefault('issue', []).append(issue_format) + else: + # 说明同一本期刊的期也重复了,那么重复的期数都不可信 + del_issue_coll.setdefault(ti_format, {}).setdefault(is_format, []).append(issue_format) + count -= 1 + if del_top_id_set: + for del_top in del_top_id_set: + result[del_top].pop('id', None) + if del_issn_id_coll: + for key_ti, vals in del_issn_id_coll.items(): + for val in vals: + result[key_ti][val].pop('id', None) + # 删除期重复的 + if del_issue_coll: + for key_ti, is_info in del_issue_coll.items(): + for ii in is_info: + for x in is_info[ii]: + count -= 1 + # 移除issn中的的期 + result[key_ti][ii].pop(x, None) + # 移除最上层的期 + result[key_ti].pop(x, None) + self._map_count += count + return result + + def make_ti_id_type2(self, datas: list): + result = {} + count = 0 + del_top_id_set = set() + del_so_coll = {} + for data in datas: + count += 1 + t_id, ti_uni = data + ti_format, so_format = ti_uni.split(':') + if not result.get(ti_format): + result.setdefault(ti_format, {}) + else: + del_top_id_set.add(ti_format) + # 需要先把标题的字典里有一个id字段 + if not result[ti_format].get('id'): + result[ti_format].setdefault('id', t_id) + else: + # 设置过id说明标题有重复,就要删除掉id字段,进行下层处理 + del_top_id_set.add(ti_format) + # 处理期刊名称 + if not result[ti_format].get(so_format): + result[ti_format].setdefault(so_format, {}) + # 在期刊名称层中设置id + result[ti_format][so_format].setdefault('id', t_id) + else: + # 说明期刊名称有重复,删除掉id + del_so_coll.setdefault(ti_format, []).append(so_format) + + if del_top_id_set: + for del_top in del_top_id_set: + result[del_top].pop('id', None) + if del_so_coll: + for key_ti, vals in del_so_coll.items(): + for val in vals: + result[key_ti][val].pop('id', None) + self._map_count += count + return result + + def ti_id_relation(self, ti_map_str: str): + count = 0 + # 类型收集 + var_map = dict() + id_ti_list = ti_map_str.split(';') + for s in id_ti_list: + count += 1 + i, ti = s.split(',') + t = ti[:TAG_TYPE_LENGTH] # 取类型标记位 + # -------------------- 没有标识类型时用默认的逻辑 -------------------- + if t not in GET_TYPE_MAP: + t = TYPE1 # 默认值为1 + else: + ti = ti[TAG_TYPE_LENGTH:] + var_map.setdefault(t, []).append((i, ti)) + case = dict() + while var_map: + t, info = var_map.popitem() + if t == TYPE1: + case[t] = self.make_ti_id_type1(info) + elif t == TYPE2: + case[t] = self.make_ti_id_type2(info) + else: + raise ValueError("%s 类型解析未实现" % t) + return case + + +if __name__ == '__main__': + """ + ti_map = TitleMatchIdTool( + id_ti_info='BLDS201706005,区域大气污染排放效率变化趋势地区差距与影响因素基于长江经济带11省市的面板数据:10093370:20176;BLDS201706004,北京机动车环境外部成本的测算:10093370:20176;BLDS201706003,个体异质性与环境公共物品的私人有效供给:10093370:20176;BLDS201706002,绿色治理变迁逻辑政策反思与展望基于19782016年政策文本分析:10093370:20176;BLDS201706001,新能源汽车产业专利池的形成机制:10093370:20176;BLDS201806021,北京理工大学学报社会科学版征稿简则:10093370:20186;BLDS201806020,北京理工大学学报社会科学版2018年总目录:10093370:20186;BLDS201806019,双一流建设高校的全要素科技创新效率研究:10093370:20186;BLDS201806018,公共财政如何促进教育公平基于广东省基础教育创强专项资金绩效评价:10093370:20186;BLDS201806017,行政裁量行为的合理性审查研究:10093370:20186;BLDS201806016,大数据视野下环境侵权诉讼证据制度的优化:10093370:20186;BLDS201806015,食品安全监管国际软法变革论食品安全全球治理的视角:10093370:20186;BLDS201806014,不动产善意取得中无权处分认定研究:10093370:20186;BLDS201806013,国民经济动员立法的必要性及重难点:10093370:20186;BLDS201806012,中国经济增长方式转变的影响因素及路径选择:10093370:20186;BLDS201806011,农地闲置治理中的村民互助地方经验与缺陷补正以四川省G村为例:10093370:20186;BLDS201806010,房价波动银行信贷与产业升级基于银行信贷中介效应检验及区域差异对比分析:10093370:20186;BLDS201806009,中国股票市场信息流关联网络基于转移熵的实证研究:10093370:20186;BLDS201806008,国家创新型城市效率评价研究基于两阶段DEA模型:10093370:20186;BLDS201806007,共享经济监管机制对感知隐私风险消费者信任及持续共享意愿的影响:10093370:20186;BLDS201806006,区域旅游业碳排放的时空差异以山东省为例:10093370:20186;BLDS201806005,中国储能产业中动力电池梯次利用的商业价值:10093370:20186;BLDS201806004,环境规制空间溢出与区域生态效率基于空间杜宾面板模型的实证分析:10093370:20186;BLDS201806003,环境约束下中国工业部门能源投入的拥塞效应:10093370:20186;BLDS201806002,陷入惩戒牢笼失信惩戒是否抑制了企业创新来自废水国控重点监测企业的证据:10093370:20186;BLDS201806001,基准线法下企业最优碳减排和产品定价决策:10093370:20186;BLDS201805022,北京理工大学学报社会科学版征稿简则:10093370:20185;BLDS201805021,社会自主性的三种提升路径:10093370:20185;BLDS201805020,朱子学与日本近世儒学的一元论倾向:10093370:20185;BLDS201805019,从共同体之善的定位到价值中立原则的悖论反思权利绝对化及其隐忧:10093370:20185;BLDS201805018,法律效力的道德条件比较分析:10093370:20185;BLDS201805017,中国刑事证人保护制度的问题与完善:10093370:20185;BLDS201805016,诉权层次论视域下的行政诉权要件探析基于诉权本质学说与诉权要件之关联性考察:10093370:20185;BLDS201805015,岛礁之辨的分歧及其消解路径:10093370:20185;BLDS201805014,中国自然灾害与长期经济增长基于VAR与VEC模型的协整分析:10093370:20185;BLDS201805013,区块链技术在政府数据治理中的应用优势挑战与对策:10093370:20185;BLDS201805012,基于三方演化博弈的网约车出行市场规制策略:10093370:20185;BLDS201805011,中国工业行业产能利用率测度分析:10093370:20185;BLDS201805010,基于VAR模型P2P网络借贷与传统金融市场之间的动态变化:10093370:20185;BLDS201805009,电子口碑平台对感知可信度及购买意愿的影响:10093370:20185;BLDS201805008,协同创新网络与组织创新绩效的关系:10093370:20185;BLDS201805007,基于网络搜索指数的股票市场微观结构特征:10093370:20185;BLDS201805006,公众环境关心指数编制及其影响因素以北京市为例:10093370:20185;BLDS201805005,公众环境治理参与行为的多层分析:10093370:20185;BLDS201805004,政府规制下废旧汽车非正规回收渠道的演化博弈:10093370:20185;BLDS201805003,中国电力消费周期的路径演化识别基于Markov区制转移模型:10093370:20185;BLDS201805002,基于改进希尔伯特黄变换算法的碳市场价格多尺度分解:10093370:20185;BLDS201805001,地方政府环境规制竞争背景下地区间的企业污染排放行为:10093370:20185;BLDS201804020,北京理工大学学报社会科学版征稿简则:10093370:20184;BLDS201804019,建国初期劳动教育的兴起与上海的地方性实践:10093370:20184;' + 'BLDS201806001,北京理工大学学报社会科学版征稿简则:10093370:20186;GDWZ202206019,2肝癌转移的免疫微环境:肝胆外科杂志;HDLG2022S2014,2U型管式蒸汽发生器内改性壁面强化传热数值研究:核动力工程;HDLG2022S2012,2高温下锆合金包壳切向微动磨蚀行为研究:核动力工程;HDLG2022S2003,2铅铋螺旋管壳侧流动传热数值模拟研究:核动力工程;ZLJS202206003,2基于对抗网络的冷水机组制冷剂泄漏故障跨工况诊断研究:制冷技术;ZLJS202206001,2高温梯级相变胶囊堆积床储热系统数值研究:制冷技术;QHDL202204013,2调相机整流电路电阻绝缘垫块灼烧问题分析及处理:青海电力;ZLJS202206014,2模糊控制与模型预测控制在空调系统中应用的研究现状:制冷技术;CCJY2022S1005,2双一流背景下一流大学毕业生就业质量评估模型的构建与应用:成才与就业;TJCX202206007,2高速铁路半封闭式声屏障脉动风压特性实车测试研究:铁路技术创新;SHGL202204029,2上海市国家高速公路命名编号调整工作实施效果评价:上海公路;SHGL202204025,2基于轨迹和气象数据的高速公路行车安全风险研究:上海公路;NTKT2022S2015,2地铁站台与轨行区的非均匀非稳态流场及热平衡仿真分析:暖通空调;XNYJ202206007,2密闭空间内10氢气浓度的氢气空气混合气体燃爆的仿真和实验研究:新能源进展;SLJX202206003,2浮式电站黑启动方式下谐波影响因素及其表征:发电技术;ZUAN202212023,2失代偿期肝硬化的新定义:肝脏;ZUAN202212005,2门静脉成纤维细胞有望成为可再生肌成纤维细胞的新来源:肝脏;ZUAN202212004,2肝窦内皮细胞介导的细胞串扰在肝纤维化中的作用:肝脏;ZUAN202212003,2药物性肝损伤的生物标志物研究进展:肝脏;YYXX202206017,22型糖尿病患者血清叶酸和维生素B:营养学报;ZUAN202212024,2原发性肝脏神经内分泌肿瘤的诊治现状:肝脏;ZUAN202212002,2固有淋巴样细胞抗肿瘤免疫新进展:肝脏;SHGL202204017,2克服无人机拍摄扰动的高精度车辆轨迹数据提取方法:上海公路;XJZZ202206009,2北京小剧场戏曲节的发展节点与编剧养成:戏剧中央戏剧学院学报;GDYJ202212006,2双极性方波场下电晕老化对环氧树脂空间电荷特性的影响:高电压技术;SDLJ202205011,2尺度效应对船舶在受限水域航行时的流场偏移影响研究:水动力学研究与进展A辑;LSBL202212014,2EBV相关性胃癌21例临床病理学分析:临床与实验病理学杂志;SXGC202212015,2面向PHF工艺的7075T6铝合金高温变形行为:塑性工程学报;LSBL202212001,2第五版WHO肾脏肿瘤新分类主要变化解读:临床与实验病理学杂志;TSZM202212001,2增强极端天气下城市治理的韧性:探索与争鸣;TSZM202212024,2提升以个人为中心的城市应急管理能力:探索与争鸣;TSZM202212019,2践行人民城市重要理念扎实推进气候适应型城市建设:探索与争鸣;TSZM202212023,2发挥新媒体平台在城市重大气象灾害风险治理中的社会协同作用:探索与争鸣;HGSZ202212001,2微反应器内连续制备拓扑结构聚合物的研究进展:化工学报;MYSY202206005,2略论电影想象力消费的三个层面:民族艺术研究;XXCB202206005,2广州市5岁以下腹泻儿童人芽囊原虫感染流行病学特征及影响因素:中国血吸虫病防治杂志;ZLDT202212006,2超长鸡舍夏季湿帘通风时舍内温度分布研究:制冷与空调;GCSJ202206010,2超精密大行程麦克斯韦磁阻驱动器磁场建模与推力分析:工程设计学报;HEBG202212014,2U50Zr螺旋十字燃料热力耦合特性分析:哈尔滨工程大学学报;HJGC202212003,2填埋场好氧修复过程碳排放特征及削减研究:环境工程;GZTX202206006,2双减背景下社会力量参与学校体育的价值困境与对策:广州体育学院学报;SDLJ202206001,2基于神经网络的船舶剖面参数化建模与辐射水动力系数预测:水动力学研究与进展A辑;ZZLL202211001,2PI3KAKT信号转导通路关键蛋白在皮肤光老化及皮肤鳞状细胞癌中的表达研究:肿瘤;SDLJ202206003,2基于虚实结合的波浪环境下船舶操纵运动机器学习建模研究:水动力学研究与进展A辑;SDLJ202206015,2仿鸮前缘突节风机叶片气动流场的数值模拟:水动力学研究与进展A辑;ZJJB202202005,2高校实验室仪器设备管理维护现存问题及对策探究:中国教育技术装备;DZXU202212013,2基于分形超表面的小型化宽带高透射率平面透镜天线:电子学报;QHMS202204002,2大学生铸牢中华民族共同体意识的内涵特征本质规律与实践进路:青海民族大学学报社会科学版;JJYS202206009,2新时代社会主义意识形态凝聚力和引领力提升的路径研究:经济与社会发展;ZJJB202214034,2航空航天方向本科实验教学改革探讨:中国教育技术装备' + ) + print(ti_map.count()) + print(ti_map.get_id_control('六地企业顾客关系管理现状调研报告:10035192:20054')) + print(ti_map.get_id_control('北京理工大学学报社会科学版征稿简则:10093370:20185')) + print(ti_map.get_id_control('北京理工大学学报社会科学版征稿简则:10093370:20186')) + print(ti_map.get_id_control('2肝癌转移的免疫微环境:肝胆外科杂志')) + """ + ti_map = TitleMatchIdTool('BJTJ200310003,当前北京经济运行中的主要问题:10065954:200310;' + 'BJTJ200310002,北京市2003年19月份主要经济指标:10065954:200310;' + 'BJTJ200310001,今年北京经济呈V字型走势:10065954:200310;' + 'BJTJ200310000,让我轻轻地告诉你:10065954:200310;' + 'BJTJ2003Z1057,动态简讯:10065954:2003Z1;' + 'BJTJ2003Z1055,统计员颂歌歌词:10065954:2003Z1;' + 'BJTJ2003Z1054,庆祝北京市统计局建局五十周年有感:10065954:2003Z1;' + 'BJTJ2003Z1053,第二回美女午后品茶费雪突发灵感统计学的故事一:10065954:2003Z1;' + 'BJTJ2003Z1052,享受快乐统计:10065954:2003Z1;' + 'BJTJ2003Z1051,数字的回响:10065954:2003Z1;' + 'BJTJ2003Z1050,从统计资料调查报告看美国社会现象之一斑:10065954:2003Z1;' + 'BJTJ2003Z1049,国际统计学会职业道德宣言讲了些什么:10065954:2003Z1;' + 'BJTJ2003Z1048,怎样避免统计基本概念与方法的误用:10065954:2003Z1;' + 'BJTJ2003Z1047,裁文匠笔戒律为先统计分析报告写作十戒:10065954:2003Z1;' + 'BJTJ2003Z1046,谈谈怎样用活统计数据:10065954:2003Z1;' + 'BJTJ2003Z1045,摩托罗拉公司成功运作电子商务案例摩托罗拉公司房地产项目网上审批系统的实施:10065954:2003Z1;' + 'BJTJ2003Z1044,应实行能源的全社会统计:10065954:2003Z1;' + 'BJTJ2003Z1043,统计方法制度改革的思考:10065954:2003Z1;' + 'BJTJ2003Z1042,北京市物流现状调查设计的问题与思考兼与北京市物流现状调查表设计者商榷:10065954:2003Z1;' + 'BJTJ2003Z1041,行政诉讼中的补证问题:10065954:2003Z1;' + 'BJTJ2003Z1040,统计执法程序及执法文书的使用与制作十三:10065954:2003Z1;' + 'BJTJ2003Z1039,兼职做统计工作也要认真对待:10065954:2003Z1;' + 'BJTJ2003Z1038,统计违法行为处罚难难在何处:10065954:2003Z1;' + 'BJTJ2003Z1037,居民睡眠用时多少北京居民生活时间分配调查系列报告之八:10065954:2003Z1;' + 'BJTJ2003Z1036,北京市劳动岗位人员需求知多少:10065954:2003Z1;' + 'BJTJ2003Z1035,难忘在希望的田野上:10065954:2003Z1;' + 'BJTJ2003Z1034,政府统计为企业微观评价提供了丰富营养:10065954:2003Z1;' + 'BJTJ2003Z1033,难说再见:10065954:2003Z1;' + 'BJTJ2003Z1032,天道酬勤记市统计局新闻发言人于秀琴:10065954:2003Z1;' + 'BJTJ2003Z1031,追忆跨越祝福:10065954:2003Z1;' + 'BJTJ2003Z1030,50年的评说抒怀寄语:10065954:2003Z1;' + 'BJTJ2003Z1029,2001年首都经济六大行业前10名按2001年经营收入排序:10065954:2003Z1;' + 'BJTJ2003Z1028,首都经济200强强在何处:10065954:2003Z1;' + 'BJTJ2003Z1027,新企业会计制度与会计准则和股份有限公司会计制度的主要差异二十:10065954:2003Z1;' + 'BJTJ2003Z1026,企业效绩评价操作细则修订八:10065954:2003Z1;' + 'BJTJ2003Z1025,2002年批发零售贸易业餐饮业年报培训测试题及答案:10065954:2003Z1;' + 'BJTJ2003Z1024,2003年固定资产投资房地产开发定期报表制度填报方法二:10065954:2003Z1;' + 'BJTJ2003Z1023,如何看待居民消费价格指数和商品零售价格指数的数据差异:10065954:2003Z1;' + 'BJTJ2003Z1022,工业主要产品产量统计数据审核要点:10065954:2003Z1;' + 'BJTJ2003Z1021,北京市消费者信心指数是怎样编制的:10065954:2003Z1;' + 'BJTJ2003Z1020,北京市第二次投入产出工作会议召开:10065954:2003Z1;' + 'BJTJ2003Z1019,消费需求扩张环境问题突出北京市人均GDP突破3000美元究竟意味着什么之二:10065954:2003Z1;' + 'BJTJ2003Z1018,北京知识经济发展进程及分析:10065954:2003Z1;' + 'BJTJ2003Z1017,北京城市竞争力状况与变化:10065954:2003Z1;' + 'BJTJ2003Z1016,北京应在哪些领域巩固和培育经济增长点:10065954:2003Z1;' + 'BJTJ2003Z1015,京房景气指数京投景气指数均呈降势:10065954:2003Z1;' + 'BJTJ2003Z1014,关于征集北京市第十二届统计科学讨论会论文的通知:10065954:2003Z1;' + 'BJTJ2003Z1013,怎样科学分析经济形势:10065954:2003Z1;' + 'BJTJ2003Z1012,稳健统计在经济指标中的应用探讨:10065954:2003Z1;' + 'BJTJ2003Z1011,关于我国数理统计学发展中存在的问题的几点思考:10065954:2003Z1') + print(ti_map) diff --git a/science_article_cnki/science_article_cnki/utils/tools.py b/science_article_cnki/science_article_cnki/utils/tools.py index e56525f..22c56b0 100644 --- a/science_article_cnki/science_article_cnki/utils/tools.py +++ b/science_article_cnki/science_article_cnki/utils/tools.py @@ -1,5 +1,16 @@ -from typing import List, Tuple -from datetime import datetime +# -*- coding: utf-8 -*- +# @Time : 2024/5/15 17:40 +# @Author : zhaoxiangpeng +# @File : tools.py + +import enum +import re +from typing import Dict, Union + +from datetime import datetime, timedelta +from urllib.parse import urlparse, quote, unquote, parse_qs + +from . import extract_rule def str2int(val, replace=0): @@ -12,6 +23,258 @@ def str2int(val, replace=0): return val -def get_today_date(fmt: str = "%Y-%m-%d"): - return datetime.today().strftime(fmt) +def replace_str(source_str, regex, replace_str=""): + """ + 916 + @summary: 替换字符串 + --------- + @param source_str: 原字符串 + @param regex: 正则 + @param replace_str: 用什么来替换 默认为'' + --------- + @result: 返回替换后的字符串 + """ + str_info = re.compile(regex) + return str_info.sub(replace_str, source_str) + + +def url_parse(url: str): + """ + url解析为dict + :param url: + :return: + """ + query = urlparse(url).query + params = parse_qs(query) + result = {key: params[key][0] if params[key].__len__() == 1 else params[key] for key in params} + return result + + +def parse_datetime(datetime_str): + """ + 解析多种格式的日期时间字符串,返回datetime对象 + + 支持的格式: + 1. YYYY-MM-DD + 2. YYYY-MM-DD HH:MM + 3. YYYY-MM-DD HH:MM:SS + + 参数: + datetime_str (str): 日期时间字符串 + + 返回: + datetime: 解析后的datetime对象 + """ + formats = [ + "%Y-%m-%d", # 2025-05-09 + "%Y-%m-%d %H:%M", # 2025-05-08 16:16 + "%Y-%m-%d %H:%M:%S" # 2025-04-15 14:40:03 + ] + + for fmt in formats: + try: + return datetime.strptime(datetime_str, fmt) + except ValueError: + continue + + return None + + +def add_year2item(item, year: Union[int, None], pub_datetime): + """ + 给关系添加年份 + :param item: CnkiIdRelationItem + :param year: 优先选择的年份,如果为None,则从tr_node中提取 + :param pub_datetime: 从node节点中提取的日期时间字符串,支持格式见 parse_datetime 方法 + :return: + """ + if not year: + # 如果meta中没有携带年份字段,从页面中解析年份 + dt = parse_datetime(pub_datetime) + if dt: + year = dt.year + if year: + item.year = year + + return item + + +def parse_retrieval(query: str): + """ + 解析aside值拼接queryJson + :param query: + :return: + """ + def func(string: str): + stand = string[1:-1] # 去除左右的中文括号 + title, value = stand.split(":", maxsplit=1) # 分割 "作者单位:湖南中医药大学(模糊)" -> [作者单位, 湖南中医药大学(模糊)] + return title, value[:-4], value[-3:-1] + cond_list = re.split(r'(AND|NOT|OR)', query) + logic = 'AND' + content = cond_list[0] + yield logic, func(content) + for i in range(1, len(cond_list), 2): + chunk = cond_list[i:i + 2] # 获取两个元素 + logic, content = chunk + yield logic, func(content) + + +def parse_updatedtime_symbol(symbol: str, today: str = None) -> tuple: + """ + 从字符串解析时间范围 + :param symbol: + :param today: + :return: + """ + if today and isinstance(today, str): + today = datetime.strptime(today, "%Y-%m-%d") + else: + today = datetime.now() + if symbol == "最近一周": + ago_day = today - timedelta(days=7) + elif symbol == "最近一月": + ago_day = today - timedelta(days=30) + elif symbol == "最近半年": + ago_day = today - timedelta(days=181) + elif symbol == "最近一年": + ago_day = today.replace(year=today.year-1) + elif symbol == "今年迄今": + ago_day = today.replace(month=1, day=1) + else: + ago_day = today + return ago_day.strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d") + + +def id_ti2map(ti_map_str: str) -> Dict[str, str]: + """ + 将third_id,标题转为标题对应id的dict + :param ti_map_str: + :return: + """ + example = { + '配额约束下考虑回收维修努力的共享单车供应链决策与协调': { + 'id': 'YUCE202202005', # 标题仅有一个时存在 + '20970145': 'YUCE202202005', # issn对应一个id + '20222': 'YUCE202202005', # 期号对应一个id + # 假设标题有多个 + # 1.不同期刊标题重复 + '00010002': 'ZHXP200101001', + '20011': 'ZHXP200101001', + # 2.同期刊同期标题重复 + '00010003': { + 'id': 'ZHXP200101001', + '20011': 'ZHXP200101001' + } + } + } + result = {} + id_ti_list = ti_map_str.split(';') + for s in id_ti_list: + i, ti = s.split(',') + # 标题可能会重复,那么标题需要时一对多 + # 预处理标题 + ti_format, is_format, issue_format = ti.split(':') + if not result.get(ti_format): + result.setdefault(ti_format, {}) + # 需要先把标题的字典里有一个id字段 + if not result[ti_format].get('id'): + result[ti_format].setdefault('id', i) + else: + result[ti_format].pop('id') + result[ti_format].setdefault(is_format, i) + result[ti_format].setdefault(issue_format, i) + # if ti in result: + # continue + # result.setdefault(ti, i) + return result + + +def get_id_from_map(ti_unique, ti_map: dict): + ti_format, is_format, issue_format = ti_unique.split(':') + obj = ti_map.get(ti_format) + if not obj: + return None + t_id = obj.get('id') + if t_id: + return t_id + for p in [is_format, issue_format]: + t_id = ti_map.get(p) + if t_id: + return t_id + + +def so2format(data): + """ + 去除刊名的特殊后綴 + :param data: + :return: + """ + if not data: + return '' + split_result = re.split(extract_rule.DEL_SOURCE_SYMBOL_PATTERN, data) + return split_result[0] + + +def ji2format(data: str): + """ + issn标准化 + :param data: + :return: + """ + if not data: + return '' + data = data.upper() + return re.sub(r'-', '', data) + + +def ti2format(data): + """ + 去除标题空格 + :param data: + :return: + """ + return replace_str(data, extract_rule.DEL_TITLE_SYMBOL_PATTERN, "") + + +def ti2unique(ti=None, ji=None, y=None, i=None): + """ + 标题加其他标志作为唯一号 + :param ti: + :param ji: 期刊issn + :param y: + :param i: + :return: + """ + if ji: + ji = ji2format(ji) + ti_unique = '{ti}:{j}:{y}{i}'.format(ti=ti, j=ji, y=y, i=i) + return ti_unique + + +def func_0(ti, todo_dic: dict): + """ + 从dic中匹配到id + :param ti: + :param todo_dic: + :return: + """ + t_id = todo_dic.get(ti) + if not t_id: + # 去掉期刊名来匹配 + ti1, jn, q = ti.split(':') + # 同理 dic里的也要去除刊名 + return t_id + + +if __name__ == '__main__': + # so2format('中国农业文摘-农业工程') + # id_ti2map('YUCE200504016,六地企业顾客关系管理现状调研报告:10035192:20054;YUCE200504015,中国电信业市场结构与X效率的实证研究:10035192:20054;YUCE200504004,基于质量合约的风险化管理初探:10035192:20054') + q1 = '(作者单位:湖南中医药大学(模糊))OR(作者单位:湖南中医学院(精确))' + q2 = '(作者单位:湖南中医药大学(模糊))OR(作者单位:湖南中医学院(模糊))OR(篇名:基于PINK1LETM1信号通路探讨何首乌苷减轻脑缺血再灌注损伤的作用机制(精确))' + q3 = '(作者单位:湖南中医药大学(模糊))OR(作者单位:湖南中医学院(模糊))AND(篇名:基于PINK1LETM1信号通路探讨何首乌苷减轻脑缺血再灌注损伤的作用机制(精确))' + g = parse_retrieval(q3) + i = 1 + for _, s in g: + print(i, _, s) + i += 1