(2021-08-10)网络爬虫学习-中国大学排名定向爬虫


教程来源:慕课课程
记录下我的学习过程
学习时长:三天

1 Requests

1.1 Requests库的安装

在anaconda中安装requests库,因为我的python环境是anaconda搭建的虚拟环境。
只需要在anaconda Prompt中输入以下代码即可:

conda install requests

安装成功后可以在cmd中试验一下。在使用pycharm调用requests库时,我需要配置其解释器,前几次碰到过这样的问题,明明用anaconda安装了模块,但是在pycharm中无法调用,后来发现就是解释器没有配置好。
在setting>Project:pyfile>Project Interpreter中配置,如下图:
pycharm解释器配置
我的是选中anaconda中安装python的位置,确认即可。
开始愉快的爬虫之旅吧!

1.2 Requests库的7个主要方法

方法说明
requests.request()构造一个请求,支撑以下各方法的基础方法
requests.get()获取HTML网页的主要方法,对应于HTTP的GET
requests.head()获取HTML网页头信息的方法,对应于HTTP的HEAD
requests.post()向HTML网页提交POST请求的方法,对应于HTTP的POST
requests.put()向HTML网页提交PUT请求的方法,对应于HTTP的PUT
requests.patch()向HTML网页提交局部修改请求,对应于HTTP的PATCH
requests.delete()向HTML页面提交删除请求,对应于HTTP的DELETE

1.2.1 request()方法

request方法:requests.request(method, url, **kwargs)
method:请求方式,对应get/put/post等7种方法,即HTTP的那些功能。
url:拟获取页面的url链接
**kwargs:13个控制访问的参数,均为可选项
1)params:字典或字节序列,作为参数增加到url中;

import requests
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('GET', 'http://python123.io/ws', params=kv)
print(r.url)

输出得到:https://python123.io/ws?key1=value1&key2=value2
通过这个方法,可以把一些键值对增加到url中,使得url再次访问时,不止访问的是这个资源,而同时带入了这些参数,而服务器根据这些参数,筛选部分资源返回回来。
2)data:字典、字节序列或文件对象,作为Request的内容;重点是作为向服务器提供或提交资源时使用。提交的资源并不放在url链接里,而是放在url链接对应位置的地方,作为数据来存储。

import requests
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('POST', 'http://python123.io/ws', data=kv)

3)json:JSON格式的数据,作为Request的内容
也是作为内容部分可以向服务器提交。
4)headers:字典,HTTP定制开头;它对应了向某一个url访问时所发起的HTTP头字段,也就是说我们可以用这个字段来定制访问某一个url的HTTP的协议头。
我们可以定义一个字典hd = {'user-agent': 'Chrome/10'}来修改HTTP协议中的user-agent字段,我们把user-agent变为Chrome/10,
r = requests.request('POST', 'http://python123.io/ws', headers=hd)那么在访问某一个链接时,我们可以把这样的字段赋给headers,此时headers再去向服务器访问时,服务器看到的user-agent字段就是Chrome/10,也即Chrome浏览器的第十个版本;这种模拟浏览器的方法就是在header字段中实现。
4)cookies:指的是字典或CookieJar,Request中的cookie,从HTTP中解析cookie
auth:是元组类型,支持HTTP认证功能
5)files:字典类型,向服务器传输文件时使用的字段

import requests
fs = {'file': open('data.xls', 'rb')}
r = requests.request('POST', 'http://python123.io/ws', files=fs)

以file和对应文件为键值对,对应到相关的url上。
6)timeout:设定超时时间,秒为单位
可设置一个timeout时间,如果在timeout时间内,我们的请求内容没有返回回来,那么将产生一个timeout的异常。

r = requests.request('GET', 'http://www.baidu.com', timeout=10)

7)proxies字段:字典类型,设定访问代理服务器,可以增加登录认证。
如下,使用两个代理,一个是http访问时使用的代理,代理中可以增加用户名跟密码的设置,我们再增加一个https的代理服务器,我们再访问百度时所使用的IP地址就是代理服务器的IP地址,使用这个字段可以有效的隐藏用户爬取网页的源IP地址的信息,能够有效地防止对爬虫的逆追踪。

import requests
pxs = {'http': 'http://user:pass@10.10.10.1:1234',
       'https': 'https:10.10.10.1:4321'}
r = requests.request('GET','http://www.baidu.com', proxies=pxs)

8)allow_redirects:True/False,默认为True,重定向开关;此开关表示允不允许对url重定向。
stream:True/False,默认为True,获取内容立即下载开关。
verify字段:True/False,默认为True,认证SSL证书开关。
sert:是保存本地SSL证书路径的字段

1.2.2 get()方法

最简单的应用方法即r=requests.get(url),构造一个向服务器请求资源的Request对象,返回一个包含服务器资源的Response对象,用r来表示返回的所有相关资源。
完整使用方法包含三个参数:requests.get(url, params=None, **kwargs)
url:拟获取页面的url链接
params:url中的额外参数,字典或字节流格式,可选
**kwargs:12个控制访问的参数

理解Response的编码:有的header中有charset,即表示有编码要求,那就,但并不是所有的网址都能返回这个值,所以就会默认编码为ISO-8859-1,但这一编码不能解析中文。当我们用encoding不能正确返回内容时,就要用apparent_encoding来从内容中分析出编码方式。

属性说明
r.encoding从HTTP header中猜测的响应内容编码方式
r.apparent_encoding从内容中分析出的响应内容编码方式 (备选编码方式)

可以通过以下代码试验:

import requests
r = requests.get('http://www.baidu.com')
# 查看状态码
print(r.status_code)
print(r.text)
print(r.encoding)
print(r.apparent_encoding)
# 改变编码方式,并输出
r.encoding = 'utf-8'
print(r.text)

1.2.3 通用代码框架

通常使用get()函数,最大的作用是使得用户访问网页变得更有效更稳定更可靠。
因为网络连接有风险,因此异常处理很重要,Requests库常用的六种连接异常,最后一种是触发生成:

异常说明
requests.ConnectionError网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPErrorHTTP错误异常
requests.URLRequiredURL缺失异常
requests.ToolManyRedirects超过最大重定向次数,产生重定向异常
requests.ConnectTimeout连接远程服务器超时异常
requests.Timeout请求URL超时,产生超时异常
r.raise_for_status()如果不是200,产生异常requests.HTTPError

代码框架如下(如果状态不是200,引发HTTPError异常,判断网络连接的正常):

def getHTMLText():
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return '产生异常'

if __name__ == '__main__':
    url = 'http://www.baidu.com'
    print(getHTMLText())

1.2.4 HTTP协议及Requests其他方法

HTTP,Hypertext Transfer Protocol,超文本传输协议,是一个基于“请求与响应”模式的、无状态的应用层协议。即用户发起请求,服务器做出响应,无状态指第一次请求和第二次请求之间没有相关的关联,应用层协议指的是该协议工作在TCP协议之上。
HTTP协议采用URL作为定位网络资源的标识。
URL格式如下:http://host[:port][path]
两个反斜杠之后有三个域,host表示合法的Internet主机域名或IP地址;port表示端口号,缺省端口为80;path是请求资源的路径。URL是通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源。
HTTP协议对资源的操作

方法说明
GET请求获取URL位置的资源
HEAD请求获取URL位置资源的响应消息报告,即获得该资源的头部信息
POST请求向URL位置的资源后附加新的数据
PUT请求向URL位置寸尺一个资源,覆盖原URL位置的资源
PATCH请求局部更新URL位置的资源,即改变该处资源的部分内容
DELETE请求删除URL位置存储的资源

用户通过GET或者HEAD获取全部信息或者头部信息,如果想将自己的资源放在URL对应的位置上就要用PUT、POST、PATCH方法。当面对庞大资源时,采用PATCH可以只修改需要的,可以节省带宽。
使用head()方法

requests.head(url,**kwargs)

**kwargs:13g个访问控制参数
使用post()及其他方法
向URL POST一个字典,自动编码为form(表单),而字符串会默认归为到data下。
put()方法与post()方法类似。

requests.post(url, data=None, json=None,**kwargs)
requests.put(url, data=None, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.delete(url, **kwargs)

1.3 Robots协议

Robots Exclusion Standard 网络爬虫排除标准
作用:网站告知网络爬虫哪些页面可以抓取,哪些不行。
形式:在网站根目录下的robots.txt文件。
在域名后,输入robots.txt,如https://www.taobao.com/robots.txt
Robots协议基本语法:
User-agent:*
Disallow:/
*代表所有,/代表根目录
如何遵守呢,网络爬虫应该可以自动或人工识别robots.txt,再进行内容爬取,爬虫爬的好,局子进的早,还是好好遵守规则。当然如果访问量小,不涉及商业利益,不违法还是可以不遵守的。

1.4 初试

1.4.1 尝试爬取淘宝京东等网站的商品信息

import requests
url1 = 'https://item.taobao.com/item.htm?id=638296572648'
url2 = 'https://item.jd.com/100023800830.html'
try:
	kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url2, headers=kv)
    # 查看状态码
    print(r.status_code)
    # 查看编码
    print(r.encoding)
    print(r.request.headers)
    r.raise_for_status()
    print(r.text[:10000])
except:
    print('爬取失败')

1.4.2 尝试向搜索引擎提交信息,并返回内容

百度的关键词接口:
https://www.baidu.com/s?wd=keyword
360关键词的接口:
https://so.com/s?q=keyword
好家伙,百度搜索会有安全验证,然后我试了试bing搜索

import requests
url = 'https://cn.bing.com/search'
kv1 = {'q': 'python'}
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url, headers=kv, params=kv1)
    r.encoding = r.apparent_encoding
    r.raise_for_status()
    print(r.text[:20000])
except:
    print('爬取失败')

然后干脆试了一下京东搜索物品,还可以,虽然不知道参数为什么两个才行,一个就不对,显示需要登陆。

import requests
url1 = 'https://search.jd.com/Search'
kv1 = {'wq': '男装', 'keyword': '男装'}
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url1, headers=kv, params=kv1)
    r.raise_for_status()
    print(r.text[:20000])
except:
    print('爬取失败')

1.4.3 IP地址归属地的自动查询

这个还好,就要弄清楚填什么关键字段,就比如其他的IP查询网址就就可能不是这么提交的。

import requests
url1 = 'https://m.ip138.com/iplookup.asp?ip='
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url1+'202.204.80.112', headers=kv)
    r.encoding = r.apparent_encoding
    r.raise_for_status()
    print(r.text[:20000])
except:
    print('爬取失败')

2 Beautiful Soup库

2.1 安装库及调用

安装还是用的conda install beautifulsoup4
但是需要注意的是调用的时候,from bs4 import BeautifulSoup
使用一个html网页来演示,获得HTML的源代码
获取源代码的方式:

  1. 在网页上手动获取
  2. requests.grt()来获取
import requests
from bs4 import BeautifulSoup
url1 = 'http://python123.io/ws/demo.html'
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url1, headers=kv)
    demo = r.text
    # 给出demo,同时给出解释器,此处为HTML的解释器
    soup = BeautifulSoup(demo, 'html.parser')
    print(soup.prettify())
    r.raise_for_status()
    print(r.text[:20000])
except:
    print('爬取失败')

因此使用bs4只需要两行

from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data</p>', 'html.parser')

第一个参数是我们需要解析的一个html格式的信息,第二个是解析器。

2.2 soup库的基本元素

Beautiful Soup类的基本元素

基本元素说明
Tag标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
Name标签的名字,<p>…的名字是’p’,格式:<tag>.name
Attributes标签的属性,字典形式组织,格式:<tag>.attrs
NavigableString标签内非属性字符串,<>…</>中字符串,格式:<tag>.string
Comment标签内字符串的注释部分,一种特殊的Comment类型

获取标题标签内容soup.title
获取链接标签soup.a,这样只能获取第一个标签内容
获取标签名字的方法soup.a.name
还可以查看该标签的父亲是soup.a.parent.name
还可以继续往上查看,使用.name的方式获取名字,使用.parent.name查看父类,以字符串类型输出
查看标签的属性信息,标签的属性是在标签中标明标签特点的相关区域,以字典形式组织,给出了属性名和属性的键值对,可以使用字典的方式对每一个属性的提取,soup.a.attrs
查看标签类型,type(soup.a),看标签类型是如何定义的:<class 'bs4.element.Tag'>
tag标签可以有0个或多个属性,当没有属性的时候使用.attrs获得的字典是空字典,但是无论有无属性都可以获得字典。
获取Tag标签的NavigableString属性,也就是两个尖括号之间的内容,使用soup.a.string,其类型为<class 'bs4.element.NavigableString'>
再html中使用<!..>来表示注释,输出注释部分可以用.string来输出,查看其类型来确认。

2.3 基于bs4的HTML内容遍历方法

需要对HTML基本格式有了解。
了解了基本格式,就可以了解几种遍历方式:

  • 从根节点到叶子节点的下行遍历方式
  • 从叶子节点到根节点的上行遍历方式
  • 在平级节点之间相互遍历
    如图:在这里插入图片描述

2.3.1 下行遍历

标签数的下行遍历一共包含三个属性

属性说明
.contents子节点的列表,将<tag>所有儿子节点存入列表
.children子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants子孙节点的迭代类型,包含所有子孙节点,用于循环遍历

对于标签的儿子节点不仅仅包括标签节点,也包括字符串节点,比如'\n'
遍历方式:

for child in soup.body.children:
	print(child)# 遍历儿子节点
for child in soup.body.descendants:
	print(child)# 遍历子孙节点

2.3.2 上行遍历

上行遍历的两个属性

属性说明
.parent节点的父亲标签
.parents节点先辈标签的迭代类型,用于循环遍历先辈节点

标签树的上行遍历代码

soup = BeautifulSoup(demo, 'html.parser')
for parent in soup.a.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)

在遍历一个标签的所有先辈标签时,会遍历到soup本身,而soup的先辈并不存在.name的信息,所以我们需要做出一个区分,如果先辈是none,我们就不能打印这方面的信息。

2.3.3 平行遍历

beautifulsoup4库一共提供了4个平行遍历属性:

属性说明
.next_sibling返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling返回按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

标签数的平行遍历是有条件的,所有的平行遍历必须发生在同一个父亲节点下,如果不是同一个父亲节点下的标签之间不构成平行遍历关系。在我们的数据结构中,title和p标签就不是,而body下的两个p标签就是平行标签。
因为存在NavigableString元素中字符串也算为节点,依次标签对应的平行节点不一定是标签。
平行遍历方式:

for sibling in soup.a.next_siblings:
	print(sibling)# 遍历后续节点
for sibling in soup.a.previous_siblings:
	print(sibling)# 遍历前续节点

2.4 基于bs4库的HTML格式化和编码

  1. 也就是让html内容更加友好地显示
    bs4库提供了prettify方法,能使每一个标签及内容分行显示。能对soup处理,也能对每个标签处理。soup.prettify()或者soup.a.prettify()
  2. 编码问题:bs4库将如何读入的html文件或字符串都转换成了UTF8编码,对python3.x系列默认的编码一致。

2.5 信息组织与提取方法

2.5.1 信息标记的三种形式

信息标记的一般种类:
XML、JSON和YAML

  1. XML是扩展标记语言,与HTML接近;采用以标签为主来构建信息表达信息的方式,<name>...</name>或者<name />内容为空时可采用一对尖括号即可,也可插入注释内容<!-- -->
  2. JSON (JavaScript Objext Notation)即它是JavaScript中对面向对象信息的一种表达形式;是有类型的键值对来构建的信息表达方式,有类型表示字符串用双引号引用,而数字则不用 等。键: 值,多值时采用键: [值1, 值2],键值对可以嵌套使用,此时用{,}的形式来体现。一般用在程序对接口处理的地方,能作为程序代码的一部分,并被程序直接运行,缺陷就是无法体现注释。
  3. YAML (YAML Ain`t Markup Language),其全称是一种递归的定义,采用的是无类型键值对来构建,也就是无论键还是值都没有双引号,以缩进的形式来描述其所属关系;用减号表达并列关系;一个键可能对应多个值,那么在每个值前就用减号来表示并列;用竖线|来表示整块数据,跨越多行或者信息量较多,用#表示注释,键值对之间可以嵌套。目前主要用于各系统的配置文件中,有注释易读。

2.5.2 信息提取的一般方法

1)完整解析信息的标记形式,再提取关键信息
需要标记解析器,如之前解析html的解析器,使用bs4的标签树来遍历。
2)无视标记形式,直接搜索关键信息(文本查找函数,如find_all()方法)
3)最好当然是结合,结合形式解析和搜索方法,提取关键信息。
例:提取html中所有URL链接
思路:第一步:搜索到所有的<a>标签
第二步,用<a>标签的解析格式,提取href属性,获得链接内容

from bs4 import BeautifulSoup
url1 = 'http://python123.io/ws/demo.html'
try:
    kv = {'user-agent': 'Mozilla/5.0'}
    r = requests.get(url1, headers=kv)
    demo = r.text
    soup = BeautifulSoup(demo, 'html.parser')
    for link in soup.find_all('a'):
        print(link.get('href'))
    r.raise_for_status()
except:
    print('爬取失败')

2.5.3 基于bs4库的HTML内容查找方法

1)
bs4库提供了一个方法来查找<>.find_all(name, attrs, recursive, string, **kwargs),这个方法可以在soup的遍历中取查找里面的信息,返回一个列表类型,存储查找的结果。

  • name:指对标签名称的检索字符串。比如soup.find_all('a'),输出一个包含所有a标签的列表;如果查找两个标签,那么可以使用soup.find_all(['a', 'b']),以列表形式作为第一个参数传递。如果我们给的标签名称是true,将显示当前soup的所有标签信息。
  • sttrs:是对标签属性值的检索字符串,可标注属性检索,可检索标签的属性中是否包含了某些字符信息,如soup.find_all('p', 'course')来检查p标签中是否包含course字符串,返回一个列表,里边给出了带有course属性值的p标签;也可以直接对属性做相关约定,例:查找ID属性等于link1的值作为查找元素,soup.find_all(id='link1'),如果没有此标签,那么会返回一个空列表。
  • recursive:是一个布尔型的值,表示是否对子孙全部检索,默认为true,如果只想搜索儿子节点层面的东西,可以改为false。
  • string:指对标签中间的字符串域进行检索的字符串参数;soup.find_all(string = re.compile('python'))

2)
由于find_all()函数很常见,所以在bs4库中有简写:<tag>(...)等价于<tag>.find_all(...),对soup变量也如此,将标签改为soup即可。
3)还有find_all()方法的扩展方法

方法说明
<>.find()搜索且只返回一个结果,字符串类型,同.find_all()参数
<>.find_parents()在先辈节点中搜索,返回列表类型,同.find_all()参数
<>.find_parent()在先辈节点中返回一个结果,字符串类型,同.find()参数
<>.find_next_siblings()在后续平行节点中搜索,返回列表类型,同.find_all()参数
<>.find_next_sibling()在后续平行节点中返回一个结果,字符串类型,同.find()参数
<>.find_previous_siblings()在前续平行节点中搜索,返回列表类型,同.find_all()参数
<>.find_previous_sibling()在前续平行节点中返回一个结果,字符串类型,同.find()参数

3 bs4实例-中国大学排名定向爬虫

3.1 实例基本情况

使用上海交大的排名网站查询:https://www.shanghairanking.cn/rankings/bcur/2021
输入:大学排名URL链接
输出:大学排名信息的屏幕输出(排名、大学名称和总分)
技术路线:requests-bs4
定向爬虫:仅对输入URL进行爬取,不扩展爬取。
程序设计:
步骤1:从网络上获取大学排名网页内容,定义函数get_html_text()
步骤2:提取网页内容中信息到合适的数据结构,定义函数text_to_list()
步骤3:利用数据结构展示并输出结果univ_list_print()
观察源代码我们发现,排名信息都存于<tbody data-v-3ba213b8="">这个表格标签中,在其中,每一个大学的所有信息又被封装在<tr><\tr>中,每一个信息又被<td><\td>所包含。所以需要先找到tbody标签,然后再tbody标签中解析tr标签,再把tr标签中的td标签找到,把相关信息找到放入列表中。

3.2 代码编写

#!/usr/bin/python

import requests
from bs4 import BeautifulSoup
import bs4


def get_html_text(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        print('爬取失败')
        return ''


def text_to_list(univ_info, html):
    soup = BeautifulSoup(html, 'html.parser')

    # 查找tbody标签,并将它的孩子做一个遍历
    for tr in soup.find('tbody').children:

        # 排除掉其他的节点非标签类的其他信息,比如字符串
        if isinstance(tr, bs4.element.Tag):

            # 获取其中td标签内容
            tds = tr('td')
            univ_info.append([tds[0].text.strip(), tds[1].text.strip(), tds[4].text.strip()])


def univ_list_print(univ_info, num):
    print('{:^10}\t{:^16}\t{:^10}'.format('排名', '学校名称', '总分'))
    for i in range(num):
        u = univ_info[i]
        print('{:^10}\t{:^16}\t{:^14}'.format(u[0], u[1][:8], u[2]))


def main():
    univ_info = []
    url = 'https://www.shanghairanking.cn/rankings/bcur/2021'
    html = get_html_text(url)
    text_to_list(univ_info, html)
    univ_list_print(univ_info, 20)  # 20所学校


if __name__ == '__main__':
    main()

1)因为教程内容是多年前的,所以有些东西需要改变,就比如将td标签内容传递入列表中需要改变方法,教程中是使用.string但是因为网址的改变,会将style="display:none"也传入列表,会有报错:TypeError: unsupported format string passed to NoneType.__format__
去网上找了解决方法:问题解决:TypeError: unsupported format string passed to NoneType.format
强哇!CSDN永远滴神!
2)刚开始发现报错是AttributeError: 'NoneType' object has no attribute 'children',是的,好多错,一个一个来,我看了下网上说的,他们是在第一个函数的时候其实就是运行错误了,但是第一个函数用了try-except来解决异常问题,所以返回空列表,造成后续的问题,没有子孙节点。他们是timeout等关键词写错了,我看了看发现是在最开始自己瞎调试的一些代码没删掉,哈哈哈哈这个问题解决了,我也是看到说传递的是空列表才反应过来,所以我在except异常处理里面加了语句:print('爬取失败')
3)输出大学名称的时候,我发现输出了很多字符串,有大学名称后边跟着大学英文名和大学标签,后来查看源代码,发现大学名称只是在<a><\a>标签中;所以有解决办法一:这个办法看起来正统一些,将a标签的内容单独导出来,传入列表。第二个方法就是,我在看输出的东西的时候,直接截取前边字符串。笑哭,我要为自己的机智折服。
4)输出的表格还是会有参差不齐,主要是因为有些大学名字太长 了,对于强迫症来说有点难受,解决办法:来源还是上边的老哥整出来的,这我是真不会。

    tplt = "{0:^10}\t{1:{3}^12}\t{2:^10}"
    # 0、1、2为槽,{3}表示若宽度不够,使用format的3号位置处的chr(12288)(中文空格)进行填充
    print(tplt.format("排名","学校名称","总分",chr(12288)))

3.3 优化实现

1)上边的解决大学名称的输出
def text_to_list(univ_info, html):该函数内容修改如下

afile = tr('a')
tds = tr('td')
univ_info.append([tds[0].text.strip(), afile[0].string, tds[4].text.strip()])

函数def univ_list_print(univ_info, num):修改

def univ_list_print(univ_info, num):
    print('{:^10}\t{:^16}\t{:^10}'.format('排名', '学校名称', '总分'))
    for i in range(num):
        u = univ_info[i]
        print('{:^10}\t{:^16}\t{:^14}'.format(u[0], u[1], u[2]))

2)对齐问题
format方法中相关的约定

<填充><对齐><宽度><.精度><类型>
引导符号用于填充的单个字符<左对齐>右对齐^居中对齐槽的设定输出宽度数字的千位分隔符适用于整数和浮点数浮点数小鼠部分的精度或字符串的最大输出长度整数类型b c d o x X浮点数类型e E f %

输出中文字符,中文字符宽度不够时,采用西文字符填充;中西文字符占用宽度不同。
优化1:
中文字符宽度不够,采用中文字符来填补
嗷!采用中文字符的空格填充chr(12288)(这个就是utf-8编码对应中文字符的空格)
排版下来就很舒服(用左对齐以及字符宽度来调就是下图这样了)
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值