最近想要做一个高考志愿填报参考的程序,需要大学的简介、专业、分数线等信息,但找了下,网上现成的数据库要么残缺不全,要么年份过于久远,因此,决定自己写个爬虫构建数据库,这里做个记录。
环境
本文开发运行使用的环境如下:
- windows 10
- sublime text 3
- Chrome
- lxml,requests
需求分析
首先,明确我们需要什么信息,这里打算提取的信息如下:
- 学校名字
- 学校简称
- 学校代码
- 学校性质
- 办学性质
- 学校地址
- 学校简介
- 主管部门
(分数线和专业信息的爬虫下次再写)
代码实现
这里分两块分别实现:
- 爬取所有教育部公布具有招生资格(非野鸡大学)的大学名单
- 爬取学校基本信息
所有大学名单爬取
这里爬取中国教育在线页面的名单
主要思想是先爬取该页面的所有省份的url链接,然后存到一个数组中,再遍历爬取每个页面的表格内容
这里遇到的问题是如何遍历tr的所有td中的内容,经过查找资料,决定先提取tr元素,再遍历列表提取每个tr中的td的内容
最终代码如下:
def getAllCollege(allCollegeUrl):
# 获取所有正规大学
html = etree.HTML(requests.get(allCollegeUrl).text)
theHTML = etree.tostring(html).decode('utf-8')
allInfo = []
# print(theHTML)
try:
theUrls = html.xpath('//div[@class="province"]/a/@href')
# print(theUrls)
except Exception as e:
print(e)
for item in theUrls:
reqResult = requests.get(item)
reqResult.encoding = 'utf-8'
tempHtml = etree.HTML(reqResult.text)
# theTempHTML = etree.tostring(tempHtml).decode('utf-8')
# print(theTempHTML)
try:
# theColleges = tempHtml.xpath('//tbody/tr/td/text()')
# print(theColleges)
theColleges = tempHtml.xpath('//tbody/tr')
for i in theColleges[2:]:
theContent = i.xpath('td/text()')
# print(theContent)
allInfo.append(theContent)
except Exception as e:
print(e)
# pass
print(allInfo)
return allInfo
高校信息爬取
上述页面爬取的信息其实如果需求不高的话,已经够用了
但是个人觉得这些信息还是有点少,于是决定去百度百科爬取更多的信息
经过观察,百度百科的url大致是https://baike.baidu.com/item/学校名称
这样的格式,这就十分好办了,因为经过上述步骤,我们已经拿到了所有大学的名字,可以以此为种子遍历请求链接获取想要的信息
将上述函数所得的结果作为参数传入,循环遍历请求,对所得的内容使用lxml进行解析即可
获取学校简介(这里部分代码参考了这篇博客):
# 爬取学校简介
summary = tempHtml.xpath('//div[@class="lemma-summary"]//text()')
summary_list_after_filter = [item.strip('\n') for item in summary]
theSummary = ''.join(summary_list_after_filter)
# 去掉参考文献标识
theSummary = re.sub('\[[\d-]+\]', '', theSummary)
# 去掉一些影响编码的字符
theSummary = theSummary.replace('\xa0', '').replace('\xad', '').replace('\u2002', ' ').replace('\ufffc', '').replace('\xb2', '').replace(',', '').replace('\n', '\\n')
# print(theSummary)
获取学校基本信息则先提取百度百科基本信息的dom元素:

考虑到名称和值使用的标签并不相同(名称为dt
,值为dd
),使用常规的匹配方法过于繁琐,于是首先提取他们的父元素dl
:
baseInfo = tempHtml.xpath('//div[contains(@class, "basic-info")]/dl//text()')
直接扁平化处理为字符串:
baseInfo = ''.join(baseInfo)
然后直接使用正则匹配所需的值,如匹配简称:
jiancheng = re.findall('简 称\n\n[\w、\u4e00-\u9fa5()]+\n', baseInfo)
jiancheng = jiancheng[0].replace('\n', '').replace('简 称', '').replace('\xa0', '') if jiancheng != [] else ''
首先正则匹配,然后根据匹配的情况,如果没有匹配到,则该值为空,否则就直接为匹配的结果,经过格式化去掉一些字符即可
其他字段同理
这里使用python的extend([value1, value2, ..., valuen])
函数直接在原列表中的二级列表追加元素
然后调用函数按行写入csv文件(注意这里的参数为a+
表示添加新行而不是覆盖写入):
def write2csv(item):
try:
with open('allCollege.csv', 'a+', newline='') as f:
f_csv = csv.writer(f)
f_csv.writerow(item)
except Exception as e:
print('\n\n' + str(e) + '\n\n')
主函数编写
依次调用函数即可实现自动爬虫爬取信息:
if __name__ == '__main__':
allCollegeUrl = 'https://daxue.eol.cn/mingdan.shtml'
allCollegesList = getAllCollege(allCollegeUrl)
getBaike(allCollegesList)
至此,代码编写完成
程序运行
直接使用命令运行即可:
python allCollege.py
运行结果如图:


可以看到,教育部公布具有招生资格的普通高等学校2740所(除港澳台地区和成人高等学校外),含本科院校1258所、高职(专科)院校1482所的信息已经全部爬取完成,脚本运行时长1506.7s
,考虑到脚本运行过程全自动(不需要人员看护,只要确保电脑联网即可),而且高校信息基本上长时间不会更新,也就是一次运行长时间收益,这个效率还是可以接受
网友评论