crawler-08 中国大学排名定向爬虫

crawler-08 中国大学排名定向爬虫

  有人的地方就有江湖,有大学的地方就有排名,这里以最好大学网为例,爬取其中的大学排名情况。

1、项目简介

1)网址:http://www.zuihaodaxue.com/Greater_China_Ranking2019_0.html2

2)robots协议:http://www.zuihaodaxue.com/robots.txt

  如下图,该网站根目录下没有robots.txt,默认任意爬虫可以无限制地对该网站进行爬取。

UTOOLS1576467170603.png

2、功能描述

1)输入:大学排名URL链接;

2)输出:大学排名信息的屏幕输出(排名,大学名称,总分);

3)技术路线:requests‐bs4;

4)定向爬虫:仅对输入URL进行爬取,不扩展爬取其他url;

3、项目准备

1)可行性分析(法律角度)

  该网站根目录下没有robots.txt,默认任意爬虫可以无限制地对该网站进行爬取。

2)可行性分析(技术角度)

  需要分析一下,我们要爬取的信息是否都写在了HTML页面之中,因为有一部分数据,可能是通过javascript等脚本语言生成的,即动态网页。动态网页有一部分数据是动态生成和提取的,在这种情况下,用requests‐bs4两个库,是无法获取其动态信息的。

  如下图,通过浏览器查看网页源代码,可以看到如下图,所需数据均可以查看到。

UTOOLS1576467239551.png

  如下图,在这个页面查找“香港大学”,将这一行html代码复制下来进行查看。

UTOOLS1576467268076.png

  复制下来的代码如下,每一个 tr 标签索引着一段信息,每一段信息对应一所大学;在每段信息中,每一个 td 标签里,分别存放着我们需要提取的“ 排名,大学名称,总分 ” 这些信息。

1
2
3
4
5
6
<tbody>
<tr><td>1</td><td class="align-left"><a target="_blank"href="World-University-Rankings/Tsinghua-University.html"><div align="left">清华大学(北京)</div></a></td><td>大陆</td><td>100</td><td class="hidden-xs">87.9</td><td class="hidden-xs">7.4</td><td class="hidden-xs">55.6</td><td class="hidden-xs">87.9</td><td class="hidden-xs">56.9</td><td class="hidden-xs">44.4</td><td class="hidden-xs">21.6</td></tr>
<tr><td>2</td><td class="align-left"><a target="_blank"href="World-University-Rankings/Peking-University.html"><div align="left">北京大学</div></a></td><td>大陆</td><td>80.5</td><td class="hidden-xs">81.4</td><td class="hidden-xs">10.2</td><td class="hidden-xs">54.3</td><td class="hidden-xs">77.0</td><td class="hidden-xs">55.4</td><td class="hidden-xs">55.6</td><td class="hidden-xs">29.2</td></tr>
<tr><td>3</td><td class="align-left"><a target="_blank"href="World-University-Rankings/The-Chinese-University-of-Hong-Kong.html"><div align="left">香港中文大学</div></a></td><td>香港</td><td>71.0</td><td class="hidden-xs">20.3</td><td class="hidden-xs">28.2</td><td class="hidden-xs">44.1</td><td class="hidden-xs">44.0</td><td class="hidden-xs">100</td><td class="hidden-xs">0.0</td><td class="hidden-xs">0.0</td></tr>
略。。。。。。
</tbody>

4、程序的结构设计

1)从网络上获取大学排名网页内容;自定义getHTMLText()方法。

  获取内容,用get() 方法即可,加上一个通用代码框架,如下。

1
2
3
4
5
6
7
8
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""

2)提取网页内容中信息到合适的数据结构;自定义fillUnivList()方法。

  将getHTMLText() 方法得到的html页面,提取相关信息存放入一个ulist列表之中;注意这个函数除了from bs4 import BeautifulSoup类以外,还需要import bs4库,因为要使用其对应的标签类型定义。

  isinstance函数检测 tr 标签的类型,如果不是bs4.element.Tag类型,则过滤掉;

  ulist.append()函数增加了ulist列表的字段:“ 排名,大学名称,总分 ” 。

  注意:ulist是一个二维列表;例如ulist[0]表示清华大学那一行,而ulist[0][0]表示的是那一行的第一列,即清华大学的排名“1”。

1
2
3
4
5
6
def fillUnivList(ulist, html):
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr('td') #等价于tds = tr.find_all('td')
ulist.append([tds[0].string, tds[1].string, tds[3].string])

3)利用数据结构展示并输出结果;自定义printUnivList()方法。

  将ulist列表之中之中的信息打印出来,num参数指定打印的元素数量;用format() 函数完成格式化输出,打印表头和表内容。

1
2
3
4
5
def printUnivList(ulist, num):
print("{:^10}\t{:^6}\t{:^10}".format("排名", "学校名称", "总分"))
for i in range(num):
u = ulist[i]
print("{:^10}\t{:^6}\t{:^10}".format(u[0], u[1], u[2]))

4)总结:

  为什么称函数为接口?例如getHTMLText(url) 函数,一头接入url,另一头接出爬取下来的网页内容,看起来就像一个方便好用的转换接头一样;

  因此,将函数称为接口,是最形象的比喻;

  正如上面的三个函数,一环套一环,一个接口接着另外一个接口,各司其职完成整个程序的功能运行,是最基础的编程思想。

5、程序源代码

1)原始代码

  此代码已经实现了预期功能,但是大学名称各有长短,导致看起来并不整齐美观,源码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# CrawUnivRankingA.py
import requests
from bs4 import BeautifulSoup
import bs4

def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""

def fillUnivList(ulist, html):
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr('td')
ulist.append([tds[0].string, tds[1].string, tds[3].string])

def printUnivList(ulist, num):
print("{:^10}\t{:^6}\t{:^10}".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/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs

main()

运行结果:

UTOOLS1576485142654.png

2)优化后的代码

  问题分析:当中文字符宽度不够时,默认采用西文字符填充;然而中西文字符占用宽度不同,导致第二列不能对齐。下面的代码利用format函数采用中文字符的空格进行填充,解决了第二列的对齐问题。

format() 函数参数定义:

  由其填充、宽度定义可知对齐问题的原因。

UTOOLS1576485252013.png

1
2
3
4
5
6
7
8
9
10
#采用中文字符的空格填充,参数如下
chr(12288)

#修改后的函数如下
def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}" #生成输出模板的变量
print(tplt.format("排名", "学校名称", "总分", chr(12288)))
for i in range(num):
u = ulist[i]
print(tplt.format(u[0], u[1], u[2], chr(12288)))

  注意事项:类似上例,对中英文混排输出问题进行优化,是爬虫之中经常要用到的手段,需要熟练掌握

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# CrawUnivRankingB.py
import requests
from bs4 import BeautifulSoup
import bs4

def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""

def fillUnivList(ulist, html):
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr('td')
ulist.append([tds[0].string, tds[1].string, tds[3].string])

def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tplt.format("排名", "学校名称", "总分", chr(12288)))
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/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs

main()

运行结果:

UTOOLS1576485738783.png

欢迎打赏,谢谢
------ 本文结束------
0%