1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > python基础学习[python编程从入门到实践读书笔记(连载六)]:数据可视化项目第17章

python基础学习[python编程从入门到实践读书笔记(连载六)]:数据可视化项目第17章

时间:2018-12-03 07:35:16

相关推荐

python基础学习[python编程从入门到实践读书笔记(连载六)]:数据可视化项目第17章

文章目录

使用APIend

项目结果:

使用plotly可视化github最受欢迎的python仓库:

修改后的可视化图表:

使用API

编写独立的程序,实现对获取的数据可视化。我们使用Web API自动请求网站的特定信息而不是整个网页。这种方式始终用的是最新的数据。

使用Web API

Web API 是网站的一部分, 用于与具体URL请求特定信息的程序交互。这种请求称为API调用。请求的数据将以易于处理的格式返回。这里的格式可以有JSON、CSV等。

依赖于外部源的大多数app依赖于API调用。

我们使用github 的API来完成工作。

这里我们要完成的任务是:编写一个程序,自动下载github上star最多的python项目信息,并对这些信息进行可视化。

GitHub的API让你能够通过API调用来请求各种信息。

在浏览器输入下面地址:

/search/repositories?q=language:python&sort=stars

然后我们会得到如下的网页信息:

这个调用返回了github当前托管了多少个python项目,还有一些关于最受欢迎的python仓库的信息。

这个调用拆开来看看

开头的/将请求发送到GitHub网站中响应API调用的部分,接下来的search/repositories让API搜索GitHub上的所有仓库。

repositories后面的问号指出需要传递一个实参。q表示查询,等号(=)让我们可以指定查询。

使用language:python指出只获取主要语言为python的仓库的信息。

后面的&sort=stars指定将项目按星级排序。

让我们看看返回的网站内容,其为格式化的数据,适合程序处理。

截取前几行如下:

"total_count": 7065328,"incomplete_results": false,"items": [{"id": 83222441,"node_id": "MDEwOlJlcG9zaXRvcnk4MzIyMjQ0MQ==","name": "system-design-primer","full_name": "donnemartin/system-design-primer","private": false,

从前几行我们可以看到,截止到目前(4月18日16点03分)GitHub总共有7,065,328个Python项目。

第二行中,"incomplete_results"的值为false,由此知道请求是成功的(并非不完整的)。倘若GitHub无法处理该API,此处返回的值将为true。

后续即为列表。列表中显示了返回的"items",包含GitHub上最受欢迎的Python项目的详细信息。

安装Requests

Requests包让Python程序能够轻松地向网站请求信息并检查返回的响应。

根据原书提供的安装方式,会报错:

python -m pip install --user requests

报错信息:

PS D:\user\文档\python\python_work\data_visualization\download_data> python -m pip install --user requestsWARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))': /simple/requests/WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))': /simple/requests/WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))': /simple/requests/WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))': /simple/requests/WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))': /simple/requests/Could not fetch URL /simple/requests/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='', port=443): Max retries exceeded with url: /simple/requests/ (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1125)'))) - skippingERROR: Could not find a version that satisfies the requirement requestsERROR: No matching distribution found for requestsPS D:\user\文档\python\python_work\data_visualization\download_data>

对于这种报错信息,我们已经习以为常了,只需要使用国内的源即可。

比如:执行下面这行代码即可成功安装requests,这里使用的是豆瓣的源。

pip install requests -i /simple --trusted-host

安装成功信息如下:

PS D:\user\文档\python\python_work\data_visualization\download_data> pip install requests -i /simple --trusted-host >>Defaulting to user installation because normal site-packages is not writeableLooking in indexes: /simpleCollecting requestsDownloading /packages/29/c1/24814557f1d22c56d50280771a17307e6bf87b70727d975fd6b2ce6b014a/requests-2.25.1-py2.py3-none-any.whl (61 kB)|████████████████████████████████| 61 kB 3.8 MB/sCollecting certifi>=.4.17Downloading /packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-.12.5-py2.py3-none-any.whl (147 kB)|████████████████████████████████| 147 kB 2.2 MB/sCollecting idna<3,>=2.5Downloading /packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl (58 kB)|████████████████████████████████| 58 kB 3.8 MB/sCollecting chardet<5,>=3.0.2Downloading /packages/19/c7/fa589626997dd07bd87d9269342ccb74b1720384a4d739a1872bd84fbe68/chardet-4.0.0-py2.py3-none-any.whl (178 kB)|████████████████████████████████| 178 kB 3.3 MB/sCollecting urllib3<1.27,>=1.21.1Downloading /packages/09/c6/d3e3abe5b4f4f16cf0dfc9240ab7ce10c2baa0e268989a4e3ec19e90c84e/urllib3-1.26.4-py2.py3-none-any.whl (153 kB)|████████████████████████████████| 153 kB 3.2 MB/sInstalling collected packages: urllib3, idna, chardet, certifi, requestsWARNING: The script chardetect.exe is installed in 'C:\Users\m1521\AppData\Roaming\Python\Python38\Scripts' which is not on PATH.Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.Successfully installed certifi-.12.5 chardet-4.0.0 idna-2.10 requests-2.25.1 urllib3-1.26.4PS D:\user\文档\python\python_work\data_visualization\download_data>

所以,当初学的小伙伴遇到了无法安装requests(其他python的包亦同样)的问题,可以使用国内的pip源。

处理API响应

编写程序, 自动执行API,找出github上star最多的python项目:

pythonrepos.py

注:这里repo是repository(仓库)的简称

# 导入requests模块import requests# 执行API调用并存储响应# 存储API调用的urlurl = '/search/repositories?q=language:python&sort=stars'# 最新的GitHub API版本为第3版,因此通过指定headers显式地要求使用这个版本的APIheaders = {'Accept': 'application/vnd.github.v3+json'}"""我们调用get()并将URL传递给它,再将响应对象赋给变量r。响应对象包含一个名为status_code的属性,指出了请求是否成功(状态码200表示请求成功)。打印status_code,核实调用是否成功。"""r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 将API响应赋给一个变量response_dict = r.json()# 处理结果print(response_dict.keys())

遇到问题

File "D:\Program Files\Python38\lib\ssl.py", line 997, in _createraise ValueError("check_hostname requires server_hostname")ValueError: check_hostname requires server_hostname

这个问题的解决,请参考笔者的另一篇博文:python遇到ValueError: check_hostname requires server_hostname解决方案

按照上述教程去掉bug之后,我们得到运行结果:

Status code: 200dict_keys(['total_count', 'incomplete_results', 'items'])

状态码为200,由此知道请求成功了。响应字典只包含三个键:‘total_count’、‘incomplete_results’和’items’。

处理响应字典

将API调用返回的信息存储到字典中,就可以处理其中的数据了。首先我们先来输出这些信息,查看是否正确,以防止对后面的可视化产生影响。

# 导入requests模块import requests# 执行API调用并存储响应# 存储API调用的urlurl = '/search/repositories?q=language:python&sort=stars'# 最新的GitHub API版本为第3版,因此通过指定headers显式地要求使用这个版本的APIheaders = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 将API响应赋给一个变量# 打印总共多少个仓库response_dict = r.json()print(f"Total repositories: {response_dict['total_count']}")# 探索有关仓库的信息# items是个列表,其中包含很多字典,每个字典都是一个python仓库的信息。# 将整个字典列表存在repo_dicts中repo_dicts = response_dict['items']print(f"Repositories returned: {len(repo_dicts)}")# 研究第一个仓库repo_dict = repo_dicts[0] # 字典列表中的第一个字典print(f"\nKeys: {len(repo_dict)}")# 这个字典包含的键数,打印所有键for key in sorted(repo_dict.keys()):print(key)

输出结果

Status code: 200Total repositories: 7066491Repositories returned: 30Keys: 74archive_urlarchivedassignees_urlblobs_urlbranches_urlclone_urlcollaborators_urlcomments_urlcommits_urlcompare_urlcontents_urlcontributors_urlcreated_atdefault_branchdeployments_urldescriptiondisableddownloads_urlevents_urlforkforksforks_countforks_urlfull_namegit_commits_urlgit_refs_urlgit_tags_urlgit_urlhas_downloadshas_issueshas_pageshas_projectshas_wikihomepagehooks_urlhtml_urlidissue_comment_urlissue_events_urlissues_urlkeys_urllabels_urllanguagelanguages_urllicensemerges_urlmilestones_urlmirror_urlnamenode_idnotifications_urlopen_issuesopen_issues_countownerprivatepulls_urlpushed_atreleases_urlscoresizessh_urlstargazers_countstargazers_urlstatuses_urlsubscribers_urlsubscription_urlsvn_urltags_urlteams_urltrees_urlupdated_aturlwatcherswatchers_count

通过上面返回的这些键,大概知道可以提取与项目有关的哪些信息。

下面我们来获取某个项目的具体信息,这里是对最受欢迎的仓库进行处理:

# 导入requests模块import requests# 执行API调用并存储响应# 存储API调用的urlurl = '/search/repositories?q=language:python&sort=stars'# 最新的GitHub API版本为第3版,因此通过指定headers显式地要求使用这个版本的APIheaders = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 将API响应赋给一个变量# 打印总共多少个仓库response_dict = r.json()print(f"Total repositories: {response_dict['total_count']}")# 探索有关仓库的信息# items是个列表,其中包含很多字典,每个字典都是一个python仓库的信息。# 将整个字典列表存在repo_dicts中repo_dicts = response_dict['items']print(f"Repositories returned: {len(repo_dicts)}")# 研究第一个仓库repo_dict = repo_dicts[0] # 字典列表中的第一个字典print("\nSelected information about the first repository:")print(f"Name: {repo_dict['name']}")print(f"Owner: {repo_dict['owner']['login']}")print(f"Star: {repo_dict['stargazers_count']}")print(f"Repository: {repo_dict['html_url']}")print(f"Created: {repo_dict['created_at']}")print(f"Updated: {repo_dict['updated_at']}")print(f"Description: {repo_dict['description']}")

运行程序,我们得到关于第一个项目的信息:

Status code: 200Total repositories: 7070180Repositories returned: 30Selected information about the first repository:Name: system-design-primerOwner: donnemartinStar: 126971Repository: /donnemartin/system-design-primerCreated: -02-26T16:15:28ZUpdated: -04-19T02:28:44ZDescription: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.

我们得到的信息有:仓库名称是sustem-design-primer ,拥有者是donnemartin,有126971人star这个项目,以及各种信息。

顺着这个仓库地址,打开GitHub查看一下,该仓库是关于大规模系统设计的, 里面知识覆盖面很广,知识结构清晰,于是我也知道为什么它是github上最火的python项目。

项目链接:

/donnemartin/system-design-primer/blob/master/README-zh-Hans.md

概括最受欢迎的仓库

我们想对其他仓库同样进行这样的操作,得到有用的信息,体现在代码中就是循环来处理。

# 导入requests模块import requests# 执行API调用并存储响应# 存储API调用的urlurl = '/search/repositories?q=language:python&sort=stars'# 最新的GitHub API版本为第3版,因此通过指定headers显式地要求使用这个版本的APIheaders = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 将API响应赋给一个变量# 打印总共多少个仓库response_dict = r.json()print(f"Total repositories: {response_dict['total_count']}")# 探索有关仓库的信息# items是个列表,其中包含很多字典,每个字典都是一个python仓库的信息。# 将整个字典列表存在repo_dicts中repo_dicts = response_dict['items']print(f"Repositories returned: {len(repo_dicts)}")# 研究第一个仓库repo_dict = repo_dicts[0] # 字典列表中的第一个字典print("\nSelected information about each repository:")for repo_dict in repo_dicts:print(f"\nName: {repo_dict['name']}")print(f"Owner: {repo_dict['owner']['login']}")print(f"Star: {repo_dict['stargazers_count']}")print(f"Repository: {repo_dict['html_url']}")print(f"Description: {repo_dict['description']}")

我们遍历整个字典列表,得到如下每个项目的信息:由于篇幅较大,没有复制过来,而是以屏幕截图的方式:

在上述输出中,如果有感兴趣的项目可以打开一看,不过不用着急,后面要可视化这些项目。

监视API的速率限制

在浏览器输入/rate_limit

我们会得到如下的响应:

{“resources”:{“core”:{“limit”:60,“remaining”:59,“reset”:1618820589,“used”:1},“graphql”:{“limit”:0,“remaining”:0,“reset”:1618820666,“used”:0},“integration_manifest”:{“limit”:5000,“remaining”:5000,“reset”:1618820666,“used”:0},“search”:{“limit”:10,“remaining”:10,“reset”:1618817126,“used”:0}},“rate”:{“limit”:60,“remaining”:59,“reset”:1618820589,“used”:1}}

我们关心的信息是搜索API的速率限制。要找到”search“,limit告诉我们,极限为每分钟10个请求,而在当前分钟内,还可执行8个请求(remaining告诉我们的)。reset值指的是配额将重置的Unix时间

或新纪元时间(1970年1月1日午夜后多少秒)。用完配额后,你将收到一条简单的响应,由此知道已到达API极限。到达极限后,必须等待配额重置。

使用Plotly可视化仓库

上面我们得到了各个仓库的信息,这里我们可以用它们创建条形图:条形图的高度表示某项目有多少个star。

代码

python_repos_visual.py

import requests# 导入Bar类和offline模块from plotly.graph_objs import Barfrom plotly import offline# 执行API调用并存储响应url = '/search/repositories?q=language:python&sort=stars'headers = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 处理结果response_dict = r.json()repo_dicts = response_dict['items']repo_names, stars = [], [] # 创建两个空列表,存放要在图表中呈现的数据for repo_dict in repo_dicts:repo_names.append(repo_dict['name'])stars.append(repo_dict['stargazers_count'])# 可视化# data包含一个字典,指定图表类型,x是项目名称,y是项目star数data = [{'type': 'bar','x': repo_names,'y': stars,}]# 使用字典定义图表布局:指定图表名称和坐标轴的标签my_layout = {'title': 'Github上最受欢迎的python项目','xaxis': {'title': 'Repository'},'yaxis': {'title': 'Stars'},}fig = {'data':data, 'layout': my_layout}offline.plot(fig, filename='python_repos.html')

改进Plotly图表

在data和my_layout这样的字典中,可以通过键值对的形式指定各种样式。

下面通过修改data字典,来定制条形:marker设置影响条形设计。我们给条形指定了一种自定义的蓝色,加上了宽1.5像素的深灰色轮廓,还将条形的不透明度设置为0.6,以免图表过于惹眼。

对于data部分的修改如下:

# 可视化data = [{'type': 'bar','x': repo_names,'y': stars,'marker':{'color':'rgb(60, 100, 150)','line':{'width':1.5, 'color': 'rgb(25, 25, 25)'},},'opacity':0.6,}]

所有代码:

import requestsfrom plotly.graph_objs import Barfrom plotly import offline# 执行API调用并存储响应url = '/search/repositories?q=language:python&sort=stars'headers = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 处理结果response_dict = r.json()repo_dicts = response_dict['items']repo_names, stars = [], []for repo_dict in repo_dicts:repo_names.append(repo_dict['name'])stars.append(repo_dict['stargazers_count'])# 可视化data = [{'type': 'bar','x': repo_names,'y': stars,'marker':{'color':'rgb(60, 100, 150)','line':{'width':1.5, 'color': 'rgb(25, 25, 25)'},},'opacity':0.6,}]my_layout = {'title': 'Github上最受欢迎的python项目','xaxis': {'title': 'Repository'},'yaxis': {'title': 'Stars'},}fig = {'data':data, 'layout': my_layout}offline.plot(fig, filename='python_repos.html')

下面来修改my_layout:

my_layout = {'title': 'Github上最受欢迎的python项目','titlefont':{'size': 28}, # 指定图表名称的字号'xaxis': {'title': 'Repository','titlefont':{'size': 24}, # 标签字号'tickfont':{'size': 14}, # 刻度标签字号},'yaxis': {'title': 'Stars','titlefont':{'size': 24},'tickfont':{'size': 14},},}

指定标题和坐标轴字号之后,图表更美观:

可运行代码

import requestsfrom plotly.graph_objs import Barfrom plotly import offline# 执行API调用并存储响应url = '/search/repositories?q=language:python&sort=stars'headers = {'Accept': 'application/vnd.github.v3+json'}r = requests.get(url, headers=headers)print(f"Status code: {r.status_code}")# 处理结果response_dict = r.json()repo_dicts = response_dict['items']repo_names, stars = [], []for repo_dict in repo_dicts:repo_names.append(repo_dict['name'])stars.append(repo_dict['stargazers_count'])# 可视化data = [{'type': 'bar','x': repo_names,'y': stars,'marker':{'color':'rgb(60, 100, 150)','line':{'width':1.5, 'color': 'rgb(25, 25, 25)'},},'opacity':0.6,}]my_layout = {'title': 'Github上最受欢迎的python项目','titlefont':{'size': 28}, # 指定图表名称的字号'xaxis': {'title': 'Repository','titlefont':{'size': 24}, # 标签字号'tickfont':{'size': 14}, # 刻度标签字号},'yaxis': {'title': 'Stars','titlefont':{'size': 24},'tickfont':{'size': 14},},}fig = {'data':data, 'layout': my_layout}offline.plot(fig, filename='python_repos.html')

end

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。