Python爬虫实战 - 爬取TIOBE TOP20语言排行榜
# Python爬虫实战 - 爬取TIOBE TOP20语言排行榜
URL: index | TIOBE - The Software Quality Company (opens new window)
IDE: PyCharm Professional
要爬取的是排名前20的语言榜单,并将其存成文本文件和生成词云。
这个榜单包括6列,分别是2022年3月的排名(Mar 2022)、2021年3月的排名(Mar 2021)、增减、程序语言(Programming Language)、占比(Ratings)、变化率(Change)。
# 前置准备
导入要用的库:
import requests
from bs4 import BeautifulSoup
import re
import wordcloud
2
3
4
requests是用来发起https请求,并获取结果的。BeautifulSoup用于解析网页html代码,re用于正则匹配,wordcloud用于生成词云。
检查网页源代码,可以发现整个榜单放id为top20的table标签下:
榜单的主体在这个table标签的tbody标签下:
而每一行都被划分在tbody一个tr标签下:
知道这些就足够了,下面编写代码。
# 获取数据
url = "https://www.tiobe.com/tiobe-index/"
res = requests.get(url)
soup = BeautifulSoup(res.text,"html.parser")
table = soup.find("table", id="top20").find("tbody").find_all("tr")
2
3
4
上述代码获取了网页html源码并解析,返回一个soup对象,使用find和find_all函数根据标签查找,获取tr标签下数据组成的列表。
接下来将其打印出来看看:
打印出了每一个tr标签下的内容,要获取的数据就在其中:
for item in table:
print(item.text)
2
那直接取出文本:
现在拿到的数据就很间接了,程序将单个标签下所有的文本都连接到了一起。
现在已经获取到了数据,接下来要做的是数据处理。
# 数据处理
现在获取的仅仅是文本,接下来要对其进行分割。
这时派上用场的是正则表达式。
这里使用re模块中的search函数:
re.search(pattern, string, flags=0) # 扫描整个字符串并返回第一个成功的匹配。
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 |
不难发现,在上面爬到的文本中,每一行的第一个数字就是语言的当前排名(1,2,3...),因此这是固定的,后面紧跟的数字是去年排名,再跟着的若干单词是语言的名字,随后两个百分数就是占比和变化率。
那么每一次循环中,都是对一行的文本中数据的提取。
首先剔除每一行的第一个数字即当前排名,那么到字母之前剩下的数字就是去年排名,可以轻易的写出正则表达式"[0-9]+",来匹配第一个出现的纯数字。
随后就是语言名字了,直接匹配第一个非数字字符串即可,即"\D+"。
接下来要匹配占比,显然这个百分数后面都会跟着一个正号或负号,因此表达式可以写成
"(\d+.([0-9]?)%+)|(\d+.([0-9]?)%-)",最后剩下的是变化率,这个百分数之前都。有正负号,所以可以直接写出"-(.?)%|+(.?)%"。最后得到的结果用.group()函数取出即可。
每一行提取出的数据放到一个元组里:
current_rand = 1
for item in table:
if current_rand < 10:
target = item.text[1:]
else:
target = item.text[2:]
previous_rand = re.search(r"[0-9]+", target).group()
language = re.search(r"(\D)+", target).group()
ratings = re.search(r"(\d+\.([0-9]*?)%\+)|(\d+\.([0-9]*?)%-)", target).group()[:-1]
change = re.search(r"-(.*?)%|\+(.*?)%", target).group()
current_rand = current_rand + 1
2
3
4
5
6
7
8
9
10
11
再循环中将结果打印:
因为最后的结果要保存,所以要定义一个列表,将元组放到列表中。
考虑到要生成词云,所以同样要定义一个字典,与程序语言名称为key,以占比为值,这里要把百分比的%去掉,然后转化为浮点数:
words = {}
result = []
current_rand = 1
for item in table:
if current_rand < 10:
target = item.text[1:]
else:
target = item.text[2:]
previous_rand = re.search(r"[0-9]+", target).group()
language = re.search(r"(\D)+", target).group()
ratings = re.search(r"(\d+\.([0-9]*?)%\+)|(\d+\.([0-9]*?)%-)", target).group()[:-1]
change = re.search(r"-(.*?)%|\+(.*?)%", target).group()
result.append((str(current_rand), previous_rand, language, ratings, change))
words[language] = float(ratings.strip("%"))
current_rand = current_rand + 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
得到列表后,保存文本文件:
f = open("result.txt", "w+")
f.write("Mar 2022 Mar 2021 Programming Language Ratings Change\n")
for item in result:
line = "{:<10}\t{:<10}\t{:<20}\t{:<10}\t{:<10}".format(item[0], item[1], item[2], item[3], item[4])
f.write(line + "\n")
f.close()
2
3
4
5
6
上述代码中使用了格式化字符串,利用了format函数,利用open函数打开一个文件,指定标志为"w+",使用write函数向其中写入数据,使用close函数最后关闭文件。
如下是生成词云的代码,width和height指定长宽,background_color制定背景色:
w = wordcloud.WordCloud(width=1000, height=700, background_color="white")
w.generate_from_frequencies(words)
w.to_file("result.png")
2
3
generate_from_frequencies接收一个字典。
最后to_file生成最后的图片文件。
完整代码如下:
import requests
from bs4 import BeautifulSoup
import re
import wordcloud
url = "https://www.tiobe.com/tiobe-index/"
res = requests.get(url)
soup = BeautifulSoup(res.text,"html.parser")
table = soup.find("table", id="top20").find("tbody").find_all("tr")
words = {}
result = []
current_rand = 1
for item in table:
if current_rand < 10:
target = item.text[1:]
else:
target = item.text[2:]
previous_rand = re.search(r"[0-9]+", target).group()
language = re.search(r"(\D)+", target).group()
ratings = re.search(r"(\d+\.([0-9]*?)%\+)|(\d+\.([0-9]*?)%-)", target).group()[:-1]
change = re.search(r"-(.*?)%|\+(.*?)%", target).group()
result.append((str(current_rand), previous_rand, language, ratings, change))
words[language] = float(ratings.strip("%"))
current_rand = current_rand + 1
f = open("result.txt", "w+")
f.write("Mar 2022 Mar 2021 Programming Language Ratings Change\n")
for item in result:
line = "{:<10}\t{:<10}\t{:<20}\t{:<10}\t{:<10}".format(item[0], item[1], item[2], item[3], item[4])
f.write(line + "\n")
f.close()
w = wordcloud.WordCloud(width=1000, height=700, background_color="white")
w.generate_from_frequencies(words)
w.to_file("result.png")
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
37
38
最后生成了如下的文本文件:
以及词云图片: