赞
踩
从 http://www.zuihaodaxue.cn/ 网站中爬取数据,获取世界大学学术排名(Top10)
xpath
或者 BeautifulSoup
语法提取数据;换汤不换药,相关解释请查阅这篇文章:Python:使用爬虫获取中国最好的大学排名数据(爬虫入门)
不过之前那篇文章介绍的是使用 BeautifulSoup
解析的 HTML
页面,这次我们再使用 XPath
来解析。
这里就不在赘述了,直接写代码。
不过我觉得转化为饼图会更直观一些,但是那样会有子图,如果有时间我会更新一下饼图看看效果会不会更好一点。
准备工作,请确保安装了以下库函数。
需要安装 pyecharts
(与 matplotlib
相比更美观,具有交互性,适合网站页面或商业报告展示)。
安装适用命令:
pip install -i http://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn pyecharts
关于如何使用请查阅 官方文档。
目标网站:http://www.zuihaodaxue.cn/ARWU2019.html
""" @author: shoo Wang @contact: wangsuoo@foxmail.com @file: demo03.py @time: 2020/5/10 0010 """ import requests as rq from bs4 import BeautifulSoup as Bs import pandas as pd import numpy as np from pyecharts.charts import Bar from pyecharts import options as opts from pyecharts.globals import ThemeType # 获取数据,就是通过访问网页,把他的html源代码拿过来 def getData(resLoc): rp = rq.get(resLoc) rp.encoding = 'utf-8' return rp.text # 最关键的部分: 数据处理,我们的目标是将文本格式的 html 网页转化为表格的形式; def dataProcessing(html, num): bs = Bs(html, features='lxml') # 获取 html 中 DOM 树的表格结构 table = bs.table.tbody.find_all('tr', limit=num, recursive=True) universityList = [] # 遍历该表格,筛选出我们需要的信息存储到 universityList 中 for tr in table: tds = tr.find_all('td') contents = [td.contents for td in tds] contents[1] = contents[1][0].contents # 这里网页中是图片,但是可以通过截取字符串获取到国家的英文简写 contents[2] = contents[2][0]['href'].split('/')[1].split('.')[0] contents = [''.join(i) for i in contents] # ['1', '哈佛大学', 'USA', '1', '100.0', '100.0', '100.0', '100.0', '100.0', '100.0', '78.2'] universityList.append(contents) # 自己写表头,因为网站上爬太复杂了 thf = ['世界排名', '学校', '国家', '在该国家的排名', '总分', '校友获奖', '教师获奖', '高被引学者', 'N&S论文', '国际论文', '师均表现'] # 转化为 DataFrame 结构,因为这种结构很好转化为 Excel pd_universityList = pd.DataFrame(np.array(universityList), columns=thf) return pd_universityList # 负责保存数据到本地磁盘 def saveData(data): data.to_excel('university.xlsx', index=False) # 数据可视化 def can_view(universityList): # 将 pandas 数据类型转化为 numpy 数组 data = np.array(universityList) # 将 data 转化为列表,只要第4个数据项到第10个数据项,且这些数据都为数字 ans = [[eval(i[da]) for i in data] for da in range(4, 11)] # 获取大学名称作为横坐标 un = [i[1] for i in data] # 在 InitOpts 中可以设置主题样式和图表的宽度 bar = (Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='2000px', height='700px')) .add_xaxis(un) .add_yaxis('总分', da1) .add_yaxis('校友获奖', da2) .add_yaxis('教师获奖', da3) .add_yaxis('高被引学者', da4) .add_yaxis('N&S论文', da5) .add_yaxis('国际论文', da6) .add_yaxis('师均表现', da7) # 设置标题, AxisOpts 是设置横坐标的每一个数据项的倾斜程度 .set_global_opts(title_opts=opts.TitleOpts(title="世界大学学术排名"), xaxis_opts=opts.AxisOpts(name_rotate=60, name="大学名称", axislabel_opts={"rotate": 25})) ) bar.render() def main(num): # 由于该网站最多有 1000 个大学,所以输入的数字不能大于 1000 ,否则什么也不做 if num >= 1000: print("数量不能大于1000") return else: url = 'http://www.zuihaodaxue.cn/ARWU2019.html' universityList = dataProcessing(getData(url), num) saveData(universityList) print("文件保存成功!") can_view(universityList) # 测试,爬取前10名大学的信息 main(10)
由于我对于 numpy
库不是很熟,所以可能有些地方对数据的处理多此一举了,还请读者指出问题所在。
运行的结果是一个 html
文件,可以直接在浏览器运行,他是使用 js
加载的。
在该函数中可以指定文件名,如果不指定则默认为 render.html
。
该方法与方法一的区别仅仅在于解析 HTML
时的方法不同,常用的方法有三种:
以上任意一种方法都可以实现,看个人喜好。这里也提供第二种方法来实现上述内容。
本项目依赖于 lxml
库。
我们只修改dataProcessing
的函数内容即可:
下面思路分析一下,一步一步的解决问题:
首先要获取这个 element
树:
html = etree.HTML(html)
然后我们先获取大学名称,在网页中打开控制台调试:
输入 XPath
语法: //tbody/tr/td/a/text()
,不会语法的可以先谷歌一下 XPath
语法:
我们以前十名大学为例,结果为:
['哈佛大学', '斯坦福大学', '剑桥大学', '麻省理工学院', '加州大学-伯克利', '普林斯顿大学', '牛津大学', '哥伦比亚大学', '加州理工学院', '芝加哥大学']
下面我们来获取图片信息:
虽然我们无法获取图片数据,但是可以通过截取字符串来获取国家的简写:
img_xpath = html.xpath('//tbody/tr//a/img/@src')[:num]
img = [i.split('/')[2].split('.')[0] for i in img_xpath]
结果为:
['USA', 'USA', 'UK', 'USA', 'USA', 'USA', 'UK', 'USA', 'USA', 'USA']
然后就是最简单的其余数据项的获取了:
nums = [[eval(j) for j in html.xpath('//tbody/tr[' + str(i + 1) + ']/td/text()')[:num]] for i in range(num)]
这行代码执行完毕之后是这样的:
[
['1', '1', '100.0', '100.0', '100.0', '100.0', '100.0', '100.0', '78.2'],
['2', '2', '75.1', '45.2', '88.5', '73.3', '79.2', '76.6', '53.8'], ... ]
就是每一行数据除去 国家名称 和 国家简称。鉴于该写法可读性较低,所以这里稍微解释一下:
XPath
获取数据之后对于每一个数字要转化为数字类型;所以下面我们要做的就是将我们之前获取的这两个数据添加到这个列表中,一个循环即可,这里使用 idx
作为下标的标记。
# 下面把 univ 和 img 加到 nums 列表中
idx = 0
for num in nums:
num.insert(1, univ[idx])
num.insert(2, img[idx])
idx += 1
后面的就和其他的一样了。
来看一下整体的代码:
""" @author: shoo Wang @contact: wangsuoo@foxmail.com @file: demo09.py @time: 2020/5/11 0011 """ import requests as rq from lxml import etree import pandas as pd import numpy as np from pyecharts.charts import Bar from pyecharts import options as opts from pyecharts.globals import ThemeType # 获取数据,就是通过访问网页,把他的html源代码拿过来 def getData(resLoc): rp = rq.get(resLoc) rp.encoding = 'utf-8' return rp.text # 最关键的部分: 数据处理,我们的目标是将文本格式的 html 网页转化为表格的形式; def dataProcessing(html, num): html = etree.HTML(html) univ = html.xpath('//tbody/tr/td/a/text()')[:num] # 大学名称 nums = [[eval(j) for j in html.xpath('//tbody/tr[' + str(i + 1) + ']/td/text()')[:num]] for i in range(num)] # 数据项 img_xpath = html.xpath('//tbody/tr//a/img/@src')[:num] img = [i.split('/')[2].split('.')[0] for i in img_xpath] # 大学国家的简称 # 合并列表 idx = 0 for num in nums: num.insert(1, univ[idx]) num.insert(2, img[idx]) idx += 1 # 自己写表头,因为网站上爬太复杂了 thf = ['世界排名', '学校', '国家', '在该国家的排名', '总分', '校友获奖', '教师获奖', '高被引学者', 'N&S论文', '国际论文', '师均表现'] # 转化为 DataFrame 结构,因为这种结构很好转化为 Excel pd_universityList = pd.DataFrame(np.array(nums), columns=thf) return pd_universityList # 负责保存数据到本地磁盘 def saveData(data): data.to_excel('university.xlsx', index=False) # 数据可视化 def can_view(universityList): # 将 pandas 数据类型转化为 numpy 数组 data = np.array(universityList) # 将 data 转化为列表 ans = [[eval(i[da]) for i in data] for da in range(4, 11)] # 获取大学名称作为横坐标 un = [i[1] for i in data] # 在 InitOpts 中可以设置主题样式和图表的宽度 bar = (Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='2000px', height='700px')) .add_xaxis(un) .add_yaxis('总分', ans[0]) .add_yaxis('校友获奖', ans[1]) .add_yaxis('教师获奖', ans[2]) .add_yaxis('高被引学者', ans[3]) .add_yaxis('N&S论文', ans[4]) .add_yaxis('国际论文', ans[5]) .add_yaxis('师均表现', ans[6]) # 设置标题, AxisOpts 是设置横坐标的每一个数据项的倾斜程度 .set_global_opts(title_opts=opts.TitleOpts(title="世界大学学术排名"), xaxis_opts=opts.AxisOpts(name_rotate=60, name="大学名称", axislabel_opts={"rotate": 25})) ) bar.render() def main(num): # 由于该网站最多有 1000 个大学,所以输入的数字不能大于 1000 ,否则什么也不做 if num >= 1000: print("数量不能大于1000") return else: url = 'http://www.zuihaodaxue.cn/ARWU2019.html' universityList = dataProcessing(getData(url), num) saveData(universityList) print("文件保存成功!") can_view(universityList) # 测试,爬取前10名大学的信息 main(10)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。