嵩天《Python网络爬虫与信息提取》实例2:中国大学排名定向爬虫
在介绍完requests库和robots协议后,嵩天老师又重点介绍了如何通过BeautifulSoup库进行网页解析和信息提取。这一部分就是在前面内容的基础上,综合运用requests库和BeautifulSoup库的知识,对软科中国大学排名进行定向爬取。
说明:爬虫练习仅为学习,不做商用,如有侵权,烦请联系删除!
目标网页:https://www.shanghairanking.cn/rankings/bcur/2021

爬取目标:爬取上海软科官网提供的中国最好大学排名,并在IDLE页面打印输出大学名称、排名、省市、总分信息
相关库名:requests/BeautifulSoup
目录
1.网页解析
2.代码设计
3.运行结果
4.问题记录
1.网页解析
打开上述软科中国大学排名页面,选择最新的2021年排名,页面显示如下:

查看页面源代码,Ctrl+F搜索北京大学,可以定位到与大学排名相关的代码位置,观察代码可知,所有的大学排名信息被封装在
标签中,其中每一个大学排名的信息则被封装在
2.代码设计
结合2021年新版的中国大学排名网页情况,对嵩天老师提供的中国大学排名爬虫源代码做了简单的修改,完整代码如下,相关讲解见注释:
#实例:中国大学排名定向爬虫
import requests
from 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_encoding
return r.text
except:
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标签,并将其内容保存为tds
a=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='https://www.shanghairanking.cn/rankings/bcur/2021'
#给出大学排名网页
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].https://www.icourse163.org/course/BIT-1001870001.
