在介绍完requests库和robots协议后,嵩天老师又重点介绍了如何通过BeautifulSoup库进行网页解析和信息提取。这一部分就是在前面内容的基础上,综合运用requests库和BeautifulSoup库的知识,对软科中国大学排名进行定向爬取。
说明:爬虫练习仅为学习,不做商用,如有侵权,烦请联系删除!
目标网页:/rankings/bcur/
爬取目标:爬取上海软科官网提供的中国最好大学排名,并在IDLE页面打印输出大学名称、排名、省市、总分信息
相关库名:requests/BeautifulSoup
目录
1.网页解析
2.代码设计
3.运行结果
4.问题记录
1.网页解析
打开上述软科中国大学排名页面,选择最新的排名,页面显示如下:
查看页面源代码,Ctrl+F搜索北京大学,可以定位到与大学排名相关的代码位置,观察代码可知,所有的大学排名信息被封装在<tbody>标签中,其中每一个大学排名的信息则被封装在<tr>标签中,大学排名、大学名称、省市、总分等信息都封装在其下的<td>标签中,这里需要注意的是,新版的大学排名中,大学名称对应的td标签中还包括中英文校名、LOGO等信息,这些信息又分别封装在<a>标签中,所以要仅打印中文大学名称的话,需要具体到查找属性为'name-cn'的a标签并存储其字符串。
2.代码设计
结合新版的中国大学排名网页情况,对嵩天老师提供的中国大学排名爬虫源代码做了简单的修改,完整代码如下,相关讲解见注释:
#实例:中国大学排名定向爬虫import requestsfrom bs4 import BeautifulSoup#从beautifulsoup4库中引入BeautifulSoup类,注意大小写import bs4#注意这里需要再引入bs4库,因为后面有bs4.element.Tag语句,不引入会报错def getHTMLText(url):#定义获取网页源代码文本内容的函数try:r=requests.get(url,timeout=30)r.raise_for_status()r.encoding=r.apparent_encodingreturn r.textexcept:print('获取网页信息失败')def fillUnivList(ulist,html):#定义获取大学排名信息的函数soup=BeautifulSoup(html,'html.parser')#使用html.parser解析器解析返回的html源代码文本for tr in soup.find('tbody').children:#使用for循环查找tbody标签,并遍历其子孙节点if isinstance(tr,bs4.element.Tag):#检测是否为tag标签不是则过滤tds=tr('td')#查找tr标签下所有的td标签,并将其内容保存为tdsa=tr('a','name-cn')#由于新版的排名中,td下的大学名称信息还包括中英文校名、LOGO等,这些又分别封装在a标签中,所以这里需要具体到查找属性为'name-cn'的a标签并存储其字符串,即大学的中文名称ulist.append([tds[0].string.strip(),a[0].string.strip(),tds[2].text.strip(),tds[4].string.strip()])#依次将大学排名、大学名称、省市(这个用string会报错)、总分信息保存到列表中,使用.strip()删除结尾的字符def printUnivList(ulist,num):#定义打印大学排名信息的函数,这里的num值打印大学的数量printmode='{0:^10}\t{1:{4}^10}\t{2:{4}^10}\t{3:^10}'#引入一个输出模板的变量这里的{4}指代中文空格chr(12288),用以填充大学名称其余空格,使得输出的字符能够对齐,并且这里选择把字符长度都设置为10,否则表头和打印内容总是对不齐print(printmode.format('排名','大学名称','省市','总分',chr(12288)))#打印表头的信息并设置打印格式for i in range(num):u=ulist[i]#使用for循环依次打印ulist列表中存储的大学排名信息,用变量u代表每所大学的信息print(printmode.format(u[0],u[1],u[2],u[3],chr(12288)))#设置打印格式依次打印每所大学的排名、大学名称、省市、总分信息def main():uinfo=[]#定义一个空列表用于填充装取大学排名信息url='/rankings/bcur/'#给出大学排名网页html=getHTMLText(url)#调用函数获取网页源代码文本fillUnivList(uinfo,html)#调用函数获取大学排名信息并填充到列表中printUnivList(uinfo,30)#调用打印大学排名信息的函数,并打印排名前30的大学信息main()
3.运行结果
运行代码后,IDLE页面结果显示如下:
4.问题记录
这里再记录一些代码测试过程中的报错信息,首先是一个命名错误:
NameError: name 'bs4' is not defined
其实是因为后面if isinstance(tr,bs4.element.Tag)这里用到了bs4而我们只引入了bs4库中的BeautifulSoup类,再在开头加上import bs4单独引入bs4库就好了。
此外,省市的打印如果用.string的话会报错如下:
TypeError: unsupported format string passed to NoneType.__format__
即此时省市信息为None值无法有效打印,修改为.text就能正常打印省市信息了。
再者,如果按照嵩天老师的代码直接打印.string的字符信息的话,发现打印出的大学排名信息是没有对齐且跨行了的,如下图所示:
解决这一问题的方案是在.string后再加入.strip()删除结尾可能存在的多余的字符。
这些问题也都在上面的完整代码中对应位置作了相应说明。之前看慕课时也练习过这个案例,当时也遇到了挺多问题的,而且也不能完全理解全部代码的含义,在有了些许经验之后再回来练习,很快就调整好代码成功打印出了目标信息,也对相关代码有了更好的理解,果然还是Practice makes perfects.
参考资料:
嵩天. Python网络爬虫与信息提取[EB/OL]./course/BIT-1001870001.