基于Request+bs4技术路线实现中国大学排名定向爬虫

基于Request+bs4技术路线实现中国大学排名定向爬虫

  • 一、前期准备
    • 1. 功能描述
    • 2. 定向爬虫可行性分析
    • 3. 程序结构设计
  • 二、代码的实现
    • 1. 函数的框架实现
    • 2. 函数功能实现,完成代码
  • 三、代码优化问题
    • 1. 优化apparent_encoding问题
    • 2. 输出结果的中文对齐问题
  • 四、回顾与总结
    • 1. 本爬虫的技术难点:
    • 2. 个人的一些体会
  • 五、参考资料

一、前期准备

1. 功能描述

爬取2018年中国最好大学的排名,中国最好大学排名2018网址
输入:大学排名URL链接
输出:大学排名信息的屏幕输出(排名,大学名称,总分)
基于Request+bs4技术路线实现中国大学排名定向爬虫_第1张图片
技术路线:requests‐bs4
定向爬虫:仅对输入URL进行爬取,不扩展爬取

2. 定向爬虫可行性分析

  1. 看所需要的信息是否在html页面信息,如果是js的动态信息,则用定向爬虫无法实现,需要其他技术路线
  2. 查看robots.txt文档了解相关的爬取权限。

3. 程序结构设计

Step1:从网络上获取大学排名网页内容——getHTMLText()
Step2:提取网页内容中信息到合适的数据结构——fillUnivList()
Step3:利用数据结构展示并输出结果——printUnivList()
提取网页内容中信息到合适的数据结构非常关键:所以我们采用一个二维列表的数据结构
从这例子可见数据结构非常重要。

二、代码的实现

1. 函数的框架实现

经过前面分析,整体框架为,需要3个功能函数和1个主函数。

import requets # 导入requests库
from bs4 import BeautifulSoup 导入BeauifulSoup库

# 我们定义函数的时候一定要把函数的结构设计好

def getHTMLText(url):# 定义getHTMLText()函数实现从网络上获取大学排名网页内容
    return "" # 输入网址,返回网页内容

def fillUnivList(ulist,html):定义fillUnivList()函数,实现提取网页内容中信息到合适的数据结构
    pass # 将html中我们需要的内容放到一个list中,所以需要两个参数

def printUnivList(ulist,num): # 定义printUnivList()函数,实现利用数据结构展示并输出结果
    print("Suc" + str(num)) # 打印学校的ulist信息,第二个参数是需要打印学校的数量
    

def main(): # 定义主函数
    uinfo = []
    url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html"
    html = getHTMLText(url) # 第一、获取html内容
    fillUnivList(uinfo,html) # 第二、提取并存储相应的信息到uinfo
    printUnivList(uinfo,20) # 第三、打印uinfo信息,20所学校

main() # 调用main()函数

2. 函数功能实现,完成代码

import requests # 导入requests库
from bs4 import BeautifulSoup # 导入BeauifulSoup库
import bs4

# 我们定义函数的时候一定要把函数的结构设计好

def getHTMLText(url):# 定义getHTMLText()函数实现从网络上获取大学排名网页内容
    try:
        r = requests.get(url,timeout = 30) # 获取
        r.raise_for_status() # 判断是否为200
        r.encoding = r.apparent_encoding # 根据网页内容确定编码方式
        return r.text # 返回以字符串形式网页的内容
    except:
        return "" # r如果发生异常就返回空字符串

# 提取和存储信息是关键
def fillUnivList(ulist,html): # 定义fillUnivList()函数,实现提取网页内容中信息到合适的数据结构
    soup = BeautifulSoup(html,"html.parser")
    for tr in soup.find('tbody').children: # 找到tbody标签,然后遍历他的子节点
        if isinstance(tr,bs4.element.Tag):
            tds = tr('td')
            ulist.append([tds[0].string,tds[1].string,tds[3].string]) # 这里要注意总得分在第四个
            
def printUnivList(ulist,num): # 定义printUnivList()函数,实现利用数据结构展示并输出结果
    print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分")) # 制作表头,采用format方法格式化输出
    for i in range(num):
        u = ulist[i] # 方便后面书写
        print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2])) # 输出数据
    

def main(): # 定义主函数
    uinfo = []
    url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html"
    html = getHTMLText(url) # 第一、获取html内容
    fillUnivList(uinfo,html) # 第二、提取并存储相应的信息到uinfo
    printUnivList(uinfo,20) # 第三、打印uinfo信息,20所学校

main() # 调用main()函数

输出结果如下:
基于Request+bs4技术路线实现中国大学排名定向爬虫_第2张图片

三、代码优化问题

从性能上,函数getHTMLText(url)中使用了 r.encoding = r.apparent_encoding,我们知道r.apparent_encoding会分析所有的页面内容来判断encoding方式,如果header里面给出了编码方式,而html页面内容又非常大的话,那么对于计算资源就是一种很大的浪费,性能要慢很多。如果是重复爬取,也会不断重复去判断编码方式,也会造成浪费。
从输出结果看(用户体验上),发现跟我们预期对的有些区别,不够美观。原因是:当中文字符宽度不够时,采用西文字符填充;中西文字符占用宽度不同
所以可以优化以上两个方面。

1. 优化apparent_encoding问题

目前想到有两种方法。
方法一:通过预先在IDLE中进行测试判断,分析其编码方式,然后再在源代码中直接赋值,如:r.encoding = ‘utf-8’
方法二:我们知道如果头部分析不出编码方式,那么r.encoding会输出“ISO-8859-1",那么我增加一个判断语句,如果r.encoding == 'ISO-8859-1’那么就执行,r.encoding = r.apparent_encoding。

2. 输出结果的中文对齐问题

解决方案:采用中文字符的空格填充chr(12288)。
优化后代码如下:

import requests # 导入requests库
from bs4 import BeautifulSoup # 导入BeauifulSoup库
import bs4

# 我们定义函数的时候一定要把函数的结构设计好

def getHTMLText(url):# 定义getHTMLText()函数实现从网络上获取大学排名网页内容
    try:
        r = requests.get(url,timeout = 30) # 获取
        r.raise_for_status() # 判断是否为200
        if r.encoding == "ISO-8859-1":
            r.encoding = r.apparent_encoding # 根据网页内容确定编码方式
        return r.text # 返回以字符串形式网页的内容
    except:
        return "" # r如果发生异常就返回空字符串

# 提取和存储信息是关键
def fillUnivList(ulist,html): # 定义fillUnivList()函数,实现提取网页内容中信息到合适的数据结构
    soup = BeautifulSoup(html,"html.parser")
    for tr in soup.find('tbody').children: # 找到tbody标签,然后遍历它的子节点
        if isinstance(tr,bs4.element.Tag): # 排除不是Tag对象的情况,进行数据过滤
            tds = tr('td') # 等价于tds = tr.find_all('td'),返回包含所有td标签的列表
            ulist.append([tds[0].string,tds[1].string,tds[3].string]) # 提取td标签中的字符串,这里要注意总得分在第四个
            
def printUnivList(ulist,num): # 定义printUnivList()函数,实现利用数据结构展示并输出结果
    tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
    print(tplt.format("排名","学校名称","总分",chr(12288))) # 制作表头,采用format方法格式化输出
    for i in range(num):
        u = ulist[i] # 方便后面书写
        print(tplt.format(u[0],u[1],u[2],chr(12288))) # 输出数据
    

def main(): # 定义主函数
    uinfo = []
    url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html"
    html = getHTMLText(url) # 第一、获取html内容
    fillUnivList(uinfo,html) # 第二、提取并存储相应的信息到uinfo
    printUnivList(uinfo,20) # 第三、打印uinfo信息,20所学校

main() # 调用main()函数

输出结果如下:
基于Request+bs4技术路线实现中国大学排名定向爬虫_第3张图片

四、回顾与总结

通过这个例子学到了很多。包括format的格式化输出的使用,以及BeautifulSoup的使用。很多地方在上面的代码没法体现,对于上面代码的每一行,如果那一行不理解,都可以在IDLE去试。
先放几张嵩天老师课件里面的图
基于Request+bs4技术路线实现中国大学排名定向爬虫_第4张图片
基于Request+bs4技术路线实现中国大学排名定向爬虫_第5张图片
基于Request+bs4技术路线实现中国大学排名定向爬虫_第6张图片

1. 本爬虫的技术难点:

  1. 通过分析网页源代码,找出中国大学排名信息的存放规律。要充分使用Ctrl+F以及F12这些快捷键,去进行定位和查找。本爬虫爬取的是一个table,所以表格是放在…,然后下一级是行数据,存放在…即table row,表格的数据放在…,即table data。这个很符合我们对于表格的认识。
  2. 中文字符对齐问题。

2. 个人的一些体会

通过这个爬虫实战,更加体会到基础的重要性,刚开始学习字符串、列表、字典等操作时,对于它们的方法和属性以及操作理解都没有那么深刻,实战中发现,不同的数据类型对应的不同的处理方式,所以特地回去补了一下这些基本的数据类型。
其次这个爬虫也让自己对于一个项目的过程有了一个更加清晰的认识,知道了如何去一步一步解决问题。写出合适的代码。
最后爬虫获得页面后怎么提取信息很重要,然后数据怎么存储也很重要,还有后面要继续学习的数据怎么去分析,这一步更重要,环环相扣,数据只有经过加工,才能变为有价值,从数据中发现规律,从而帮助我们进行决策,从而获利!

五、参考资料

北京理工大学嵩天老师的《Python网络爬虫与信息提取》
【注】文中图片来源于嵩天老师的课件。

你可能感兴趣的:(爬虫)