前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python:使用爬虫获取世界大学学术排名存储到 Excel 并作可视化输出

Python:使用爬虫获取世界大学学术排名存储到 Excel 并作可视化输出

作者头像
wsuo
发布2020-07-31 15:38:54
1.3K0
发布2020-07-31 15:38:54
举报
文章被收录于专栏:技术进阶之路技术进阶之路

文章目录
  • 问题描述
  • 问题分析
  • 结果展示
  • 代码实现
    • 解法一:BeautifulSoup 解析 HTML
    • 解法二:XPath 解析 HTML

问题描述

http://www.zuihaodaxue.cn/ 网站中爬取数据,获取世界大学学术排名(Top10)

  • 爬取的数据保存为Excel文件(.xlsx)
  • 进一步考虑,数据可视化输出(附加)
  • 采用 xpath 或者 BeautifulSoup 语法提取数据;

问题分析

换汤不换药,相关解释请查阅这篇文章:Python:使用爬虫获取中国最好的大学排名数据(爬虫入门)

不过之前那篇文章介绍的是使用 BeautifulSoup 解析的 HTML 页面,这次我们再使用 XPath 来解析。

这里就不在赘述了,直接写代码。

结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
数据分析
数据分析

不过我觉得转化为饼图会更直观一些,但是那样会有子图,如果有时间我会更新一下饼图看看效果会不会更好一点。

代码实现

准备工作,请确保安装了以下库函数。

需要安装 pyecharts(与 matplotlib 相比更美观,具有交互性,适合网站页面或商业报告展示)。

安装适用命令:

代码语言:javascript
复制
pip install -i http://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn pyecharts
在这里插入图片描述
在这里插入图片描述

关于如何使用请查阅 官方文档。

代码语言:javascript
复制
目标网站:http://www.zuihaodaxue.cn/ARWU2019.html

解法一:BeautifulSoup 解析 HTML

代码语言:javascript
复制
"""
@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

解法二:XPath 解析 HTML

该方法与方法一的区别仅仅在于解析 HTML时的方法不同,常用的方法有三种:

  • BeautifulSoup
  • XPath
  • Regular Expression

以上任意一种方法都可以实现,看个人喜好。这里也提供第二种方法来实现上述内容。

本项目依赖于 lxml 库。

我们只修改dataProcessing的函数内容即可:

下面思路分析一下,一步一步的解决问题:

首先要获取这个 element 树:

代码语言:javascript
复制
html = etree.HTML(html)

然后我们先获取大学名称,在网页中打开控制台调试:

输入 XPath 语法: //tbody/tr/td/a/text() ,不会语法的可以先谷歌一下 XPath 语法:

在这里插入图片描述
在这里插入图片描述

我们以前十名大学为例,结果为:

代码语言:javascript
复制
 ['哈佛大学', '斯坦福大学', '剑桥大学', '麻省理工学院', '加州大学-伯克利', '普林斯顿大学', '牛津大学', '哥伦比亚大学', '加州理工学院', '芝加哥大学']

下面我们来获取图片信息:

虽然我们无法获取图片数据,但是可以通过截取字符串来获取国家的简写:

代码语言:javascript
复制
img_xpath = html.xpath('//tbody/tr//a/img/@src')[:num]
img = [i.split('/')[2].split('.')[0] for i in img_xpath]

结果为:

代码语言:javascript
复制
['USA', 'USA', 'UK', 'USA', 'USA', 'USA', 'UK', 'USA', 'USA', 'USA']

然后就是最简单的其余数据项的获取了:

代码语言:javascript
复制
nums = [[eval(j) for j in html.xpath('//tbody/tr[' + str(i + 1) + ']/td/text()')[:num]] for i in range(num)]

这行代码执行完毕之后是这样的:

代码语言:javascript
复制
[
   ['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 获取数据之后对于每一个数字要转化为数字类型;
  • 外面的大列表负责控制小列表的个数,同时保存到 nums 中。

所以下面我们要做的就是将我们之前获取的这两个数据添加到这个列表中,一个循环即可,这里使用 idx 作为下标的标记。

代码语言:javascript
复制
# 下面把 univ 和 img 加到 nums 列表中
idx = 0
for num in nums:
    num.insert(1, univ[idx])
    num.insert(2, img[idx])
    idx += 1

后面的就和其他的一样了。


来看一下整体的代码:

代码语言:javascript
复制
"""
@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)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 问题描述
  • 问题分析
  • 结果展示
  • 代码实现
    • 解法一:BeautifulSoup 解析 HTML
      • 解法二:XPath 解析 HTML
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档