利用爬虫自动查找重名的高校

 

一句话介绍 – 这是什么

 

利用Python+百度百科,自动查阅Excel表格中的学校是否因更名而重复出现,如“XX学院”在某一年更名为“XX大学”,但表格中同时出现了“XX学院”和“XX大学”,其实是同一所学校,我们要做的就是把这样的学校找出来。

 

 

一句话思路 – 做什么

 

思路很简单,利用Python爬虫遍阅百度百科,把每个学校原始的、曾经使用的、现在的名字都找出来并记下来,然后回到Excel表格中寻找这些名字中是否出现名字重复项,如果是的话说明重复项是更名前后的同个学校。

 

背景 – 为啥要做

 

虽然现在我是做运营,整天出卖自己的机智,可是偶尔动脑筋、写代码才是真爱。

 

老板说这里有个包含3000多个中国高校的Excel表格,要我们查漏补缺。我们多找出了100个左右的新的高校,那么问题来了:这100个可能是原数据没有、新增的,也可能与原数据的某个高校是同个学校,只是因学校更名的原因于是再次出现而已。

 

出于对技术的热情和对重复性工作的抵抗,于是撸了这份代码。

 

思路分解 – 怎么做

 

核心部分有这两个。

 

1、构建学校名称集合

假如我们现在有了这100个新的高校的所有名字集合,大概如下图

 

最左边是我们新增的学校的名称,右边大括号{}内的内容就是通过百科查找到的该学校原始的、曾经使用的、现在的所有名字的集合。名字集合里面有些误差,比如出现“政府批准同意将”等字眼,这是目前程序缺陷、无法精准打击的原因,但是对后面查重影响不大。

 

我把这个函数称为get_schools_dict(),这个函数返回一个字典(dict),这个字典的key就是我们新增的那100个学校,value就是找到的名称集合。这里利用的是的爬虫爬取百科页面+正则表达式提取“更名”、“原名”等关键词前后的带有“大学/学院/学校”的字眼的文字。通常这段文字就是学校名称或者一段包含有学校名称句子。

 

2、遍历查重

让程序遍历Excel表格,查找原数据3000多个高校名是否在我们构建的100个高校名称集合中出现。如果出现的话,说明是同个高校,保存下来。

 

这里我称该函数为compare(),它会返回一个列表,列表内有若干元组(tuple),每个元组就是重名学校的原名和现在的名字,大概如下

 

代码撸起

 

整个代码结构如下

 

各个函数作用分别是读取Excel表格、从表格中得到我们想要的学校名单、构造百科的url(用于爬虫爬取)、访问url并获取百科页面、构造学校名称集合、遍历查重。在主函数中,利用以上各函数,先读取表格,然后分别获取原始高校的名单和新的100个高校的名单,然后构建新100个高校的学校名称集合,最后通过compare比较得出重名项。

 

1、完成get_schools_dict()函数。

把新增100个高校名单传进来,我们逐一取出学校名字,借助前面的get_url()、get_page()函数来得到这个高校的百科页面,然后就是重头戏:正则提取学校名称。

 

这里分为三种。

 

第一种,抓取页面上的“更名(为)”后面的带有“大学/学院/学校”字眼的文字。如下图中,“更名为”后面的“河北唐山矿冶学院”、“河北矿冶学院”就被捕捉到了,这种方法一打一个准。

 

第二种,抓取页面上的“更名(为)”前面的带有“大学/学院/学校”字眼的文字。这种通常就会出现前面说的多余的字眼。不过没关系,能把XX大学/学院/学校抓下来就行了。

 

第三种,有些百科页面会说这个学校原名是什么,那就把“原名(为:)”后的带有“大学/学院/学校”字眼的文字抓取下来。

正则表达式的教程暂不赘述,具体可详见:

http://blog.csdn.net/michaelpp/article/details/9631979

 

’[\u4e00-\u9fa5]’表示匹配任何中文,’ |’表示“或”,能保证XX大学或者XX学院或者XX学校都能匹配到。

 

这里有个缺陷,就是有些页面上会的学校名称会带有双引号或者’《’、’》’等符号,那么我们的正则表达式可能就匹配不到了,于是我们在’[\u4e00-\u9fa5]’把这些可能出现的符号也加进去,变成’ [\“\”\《\》\u4e00-\u9fa5]’,用于过滤出学校名的正则表达式最终变成:

    for school in schools_list:
        url = get_url(school)
        page_data = get_page(url)

        new_names = re.findall('更名[为\:]([\“\”\《\》\u4e00-\u9fa5]*?大学|[\“\”\《\》\u4e00-\u9fa5]*?学院|[\“\”\《\》\u4e00-\u9fa5]*?学校)',page_data)
        original_names = re.findall('([\“\”\《\》\u4e00-\u9fa5]*?大学|[\“\”\《\》\u4e00-\u9fa5]*?学院|[\“\”\《\》\u4e00-\u9fa5]*?学校)[\“\”\《\》\u4e00-\u9fa5]*?更名',page_data)
        first_name = re.findall('原名[为\:]([\“\”\《\》\u4e00-\u9fa5]*?大学|[\“\”\《\》\u4e00-\u9fa5]*?学院|[\“\”\《\》\u4e00-\u9fa5]*?学校)',page_data)

 

最后把找出来的这三种名称集中在一起,通过集合(set)的或操作(|=)可以有效的去除重复的名字,代码如下

        names = new_names+original_names+first_name
        if len(names) != 0:
            schools.setdefault(school,set())
            for name in names:
                schools[school] |= {name}

 

其中’schools.setdefault(school,set())’是指为schools这个字典创建一个item,key是school即我们要正在操作的这个学校名称,value是一个空的集合(set),这个集合再通过‘schools[school] |= {name}’把刚刚在百科上找到的那些名字都收揽了进来。

 

如果以上三句正则表达式中都找不到任何相关信息,即代码中的’names’为空,那么我们知道在百科中关于这个学校找不到任何“更名”、“原名”的信息,我们把这个学校认为是没改名过、确定是新增的高校。因此在’else’里面进行操作,如下

        else:
            print (school,'从未更名')
            schools_not_changed.append(school)

 

把他打印出来,并添加到另一个列表中。至此该函数基本完成。

 

2、撸compare函数

如果从上一步得到的字典中拿出一个一个学校,比如’漳州卫生职业学院’,它的所有名字是这样的:

 

再从原数据中拿出一个学校名称,比如’漳州医学护理职业学院’,然后通过’in’这个语句分别判断’漳州医学护理职业学院’是否在'漳州卫生学校', '日福建省人民政府批准同意将漳州医学护理职业学院', '漳州卫生职业学院'这三个里面出现。

            for school_new_name in schools_new_dict[school_new]:
                if school_original in school_new_name:
                    print ('one school be found:',school_original,'->',school_new,'\n')
                    schools_changed.append((school_original,school_new))

 

我们可以清楚看到,原名称’漳州医学护理职业学院’出现在名称集合的'日福建省人民政府批准同意将漳州医学护理职业学院'中。说明’漳州医学护理职业学院’与’漳州卫生职业学院’有一腿,即是同个学校的更名前后的两个名称。

 

这里用上了两个小变量来做标记。分别是reName和repeat。还是上面的例子,reName是指当’漳州医学护理职业学院’在'漳州卫生学校', '日福建省人民政府批准同意将漳州医学护理职业学院', '漳州卫生职业学院'的其中某一个出现的时候,reName标记为1,表示原始数据在新增的100个高校的其中某一个(即’漳州卫生职业学院’)找到了重名;而repeat是指,档’漳州医学护理职业学院’不仅在’漳州卫生职业学院’的名称集合中找到了重名,还可能在其他的100个高校名称比如‘广东开放大学’、‘广东南方职业学院’等这些学校里的名称集合也找到了重名,这种情况出现的时候,表明这几所大学可能是合并过,或者是其他更复杂的情况,应引起重视,于是我们找到repeat大于1的学校时应把它“抓”出来并且最终人工查阅、排除一下。

 

最终compar()函数函数代码如下

 

def compare(school_original_list,schools_new_dict):
    schools_changed = []
    schools_repeat = []
    for school_original in school_original_list:
        repeat = 0
        for school_new in schools_new_dict:
            reName = 0
            for school_new_name in schools_new_dict[school_new]:
                if school_original in school_new_name:
                    reName = 1
            if reName == 1:
                print ('one school be found:',school_original,'->',school_new,'\n')
                repeat += 1
                schools_changed.append((school_original,school_new))
        if repeat > 1:
            print ('\t',school_original,' repeat ',repeat,'\n')
            schools_repeat.append(school_original)
    return schools_changed,schools_repeat

 

3、其他函数

 

其他辅助性函数非常简单。

 

get_url()函数构建url。通过观察可以发现,每个高校的词条可由这样的结构组成:

’http://baike.baidu.com/item/’+’学校名称’

 

浏览器友好的把’ 万博科技职业学院’显示了出来,但在实际的url中这些中文是经过编码了的,实际的url应该是:

http://baike.baidu.com/item/%E4%B8%87%E5%8D%9A%E7%A7%91%E6%8A%80%E8%81%8C%E4%B8%9A%E5%AD%A6%E9%99%A2

 

可以看到‘%’后面一大堆东西就是中文编码后对应的符号,我们要提交如上格式的代码。

 

这里使用了urllib库的urllib. parse功能来编码中文、构建url,用法是:

‘parse.quote(word)’,其中word正是你想编码的中文内容。

最终代码如下

 

def get_url(word):
    url = 'http://baike.baidu.com/item/{}'.format(parse.quote(word))
    return url

 

get_page()函数爬取页面。这里利用了requests这个第三方库。用自带的urllib也是可以的,只是requests用熟手了。

def get_page(url):
    crawler = requests.session()
    page = crawler.get(url).content
    page_data = page.decode()
    return page_data

 

get_table()主要读取Excel表格。也是利用了第三方库xlrd,使用非常简单。

def get_table():
    data = xlrd.open_workbook('schools.xls')
    table = data.sheets()[0]
    nrows = table.nrows
    ncols = table.ncols
    return table,nrows,ncols

 

这里不仅返回了整个表,还返回了表的行数、列数等。

 

最后我们还可以写个函数,利用xlwt把更名了的学校的新名字自动写进Excel表格中。不过这里发现更名的其实不是特别多,且时间有限,暂时没有动手。那么全部代码基本到处为止就完成了。

 

改进空间

 

这代码其实很简单,也有不少缺陷。

 

一个缺陷就是各种情况没有考虑完全,比如有些百科页面是会出现‘<…>XX学院<…>更名为…’之类的想不到的情况,其中<>表示HTML语言,可能是为了给这个学校加粗、加颜色或者添加链接等;也比如整个页面没出现“更名”、“原名”这两个字眼,但是通过“创立”、“合并为”这些类似的字眼来说明这个学校的更名历史,这也是该程序暂时没能识别的。

 

改进的话要再考虑种种可能的情况,甚至可以尝试使用机器学校的方法来识别。这些就等有机会再慢慢改或者等向他人学习之后再来动工吧。

转载于:https://www.cnblogs.com/IvanPc/p/4640859.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值