20214302《Python程序设计》实验四 Python综合实践实验报告

20214304《Python程序设计》实验四 Python综合实践实验报告

 

课程:《Python程序设计》
班级: 2143
姓名: 单宇航
学号: 20214302
实验教师:王志强
实验日期:2022年5月27日
必修/选修:公选课

 

一、实验内容

1.实验题目:

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)

注:在华为ECS服务器(OpenOuler系统)和物理机(Windows/Linux系统)上使用VIM、PDB、IDLE、Pycharm等工具编程实现。

2.实验内容:

爬虫+数据处理+可视化  

   利用爬虫爬取Bilibili动漫排行榜的信息并保存到本地txt文件中,将其中的相关数据存储到excel表格中(即动漫的名字、更新集数、播放量、收藏量),将其进行可视化处理,即制作出播放量与收藏量的柱状图和条形图进行比较和分析。

网址:https://www.bilibili.com/v/popular/rank/bangumi

 

 

 

 

二、实验过程及结果  

 

实验过程:

1.调用库:re, pandas, bs4(BeautifulSoup), matplotlib.pyplot, openpyxl

import re
import pandas
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
from matplotlib import font_manager

 

2.进行网页内容的爬取和保存

def main():
    url = 'https://www.bilibili.com/v/popular/rank/bangumi'  # 所要爬取的网址
    html = get_html(url)  # 获取返回值
    # print(html)
    info = save(html)   
    view(info)         # 重新调整张量维度,张量(Tensor)的目的是能够创造更高维度的矩阵、向量

def get_html(url):
    try:
        r = requests.get(url)  # 使用get来获取网页数据
        r.raise_for_status()  # 如果返回参数不为200,抛出异常
        r.encoding = r.apparent_encoding  # 获取网页编码方式
        return r.text  # 返回获取的内容
    except:
        return '错误'

# 解析网页
def save(html):
    soup = BeautifulSoup(html, 'html.parser')  # 指定Beautiful的解析器为“html.parser”

    with open('D:/爬虫测试/data1.txt', 'r+', encoding='UTF-8') as f:
        f.write(soup.text)  

 

 

3.将所需信息从爬取的内容中提取出来

 

    # 定义好相关列表准备存储相关信息
    name = []  # 动漫名字
    jsk = []   #集数库
    bfl = []  # 播放量
    scs = []  # 收藏数


    # ********************************************  动漫名字存储
    for tag in soup.find_all('div', class_='info'):
        # print(tag)
        bf = tag.a.string
        name.append(str(bf))
    print(name)

    # ********************************************  动漫集数
    for tag in soup.find_all('div', class_='detail'):
        # print(tag)
        js = tag.find('span', class_='data-box').get_text()
        js = re.search(r'\d*(\.)?\d', js).group()
        jsk.append(int(js))
    print(jsk)
    # ********************************************  动漫播放量
    for tag in soup.find_all('div', class_='detail-state'):
        # print(tag)
        bf = tag.find('span', class_='data-box').get_text()
        # 统一单位为‘万’
        if '亿' in bf:
            num = float(re.search(r'\d(.\d)?', bf).group()) * 10000
            # print(num)
            bf = num
        else:
            bf = re.search(r'\d*(\.)?\d', bf).group()
        bfl.append(float(bf))
    print(bfl)

    # ********************************************  收藏数
    for tag in soup.find_all('div', class_='detail-state'):
        sc = tag.find('span', class_='data-box').next_sibling.next_sibling.get_text()
        sc = re.search(r'\d*(\.)?\d', sc).group()
        scs.append(float(sc))
    print(scs)

#黄色部分下面内容会讲

 

4.将上述数据存入excel表格

    # 存储至excel表格中
    info = {'动漫名': name,'集数库': jsk, '播放量(万)': bfl, '收藏数(万)': scs}     
    dm_file = pandas.DataFrame(info)
    dm_file.to_excel('Data.xlsx', sheet_name="动漫数据分析")
    # 将所有列表返回
    return name, jsk, bfl, scs

 

5.制作柱状图和折线图


#使图上的数据可以显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] #运行配置参数中的字体(font)为黑体(SimHei
plt.rcParams['axes.unicode_minus'] = False #运行配置参数总的轴(axes)正常显示正负号(minus
# **********************************************************************播放量和收藏量数对比
# *******播放量条形图
fig, ax1 = plt.subplots()
plt.bar(dm_name, dm_play, color='cyan')
plt.title('播放量和收藏量数据分析')
plt.ylabel('播放量(万)')
ax1.tick_params(labelsize=6)
plt.xticks(rotation=90, color='green')

# *******收藏量折线图
ax2 = ax1.twinx() # 组合图必须加这个
ax2.plot(dm_favorite, color='green') # 设置线粗细,节点样式
plt.ylabel('收藏量(万)')
plt.plot(1, label='播放量', color="cyan", linewidth=5.0)
plt.plot(1, label='收藏量', color="green", linewidth=1.0, linestyle="-")
plt.legend()
plt.savefig(r'D:/爬虫测试/1.png', dpi=1000, bbox_inches='tight')


plt.show()

 

5.最后设置python程序的模拟入口,正确的入口对应出口

if __name__ == '__main__':
    main()

 

6.最终完整代码:

import re
import pandas
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
from matplotlib import font_manager


def get_html(url):
try:
r = requests.get(url) # 使用get来获取网页数据
r.raise_for_status() # 如果返回参数不为200,抛出异常
r.encoding = r.apparent_encoding # 获取网页编码方式
return r.text # 返回获取的内容
except:
return '错误'


def save(html):
# 解析网页
soup = BeautifulSoup(html, 'html.parser') # 指定Beautiful的解析器为“html.parser”

with open('D:/爬虫测试/data1.txt', 'r+', encoding='UTF-8') as f:
f.write(soup.text)

# 定义好相关列表准备存储相关信息
name = [] # 动漫名字
jsk = [] #集数库
bfl = [] # 播放量
scs = [] # 收藏数


# ******************************************** 动漫名字存储
for tag in soup.find_all('div', class_='info'):
# print(tag)
bf = tag.a.string
name.append(str(bf))
print(name)

# ******************************************** 动漫集数
for tag in soup.find_all('div', class_='detail'):
# print(tag)
js = tag.find('span', class_='data-box').get_text()
js = re.search(r'\d*(\.)?\d', js).group()
jsk.append(int(js))
print(jsk)
# ******************************************** 动漫播放量
for tag in soup.find_all('div', class_='detail-state'):
# print(tag)
bf = tag.find('span', class_='data-box').get_text()
# 统一单位为
if '亿' in bf:
num = float(re.search(r'\d(.\d)?', bf).group()) * 10000
# print(num)
bf = num
else:
bf = re.search(r'\d*(\.)?\d', bf).group()
bfl.append(float(bf))
print(bfl)

# ******************************************** 收藏数
for tag in soup.find_all('div', class_='detail-state'):
sc = tag.find('span', class_='data-box').next_sibling.next_sibling.get_text()
sc = re.search(r'\d*(\.)?\d', sc).group()
scs.append(float(sc))
print(scs)

# 存储至excel表格中
info = {'动漫名': name,'集数库': jsk, '播放量()': bfl, '收藏数()': scs}
dm_file = pandas.DataFrame(info)
dm_file.to_excel('Data.xlsx', sheet_name="动漫数据分析")
# 将所有列表返回
return name, jsk, bfl, scs

def view(info):
#取出列表数据
dm_name = info[0] # 番剧名
dm_episodes = info[1] # 动漫集数
dm_play = info[2] # 番剧播放量
dm_favorite = info[3] # 番剧收藏数

#使图上的数据可以显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] #运行配置参数中的字体(font)为黑体(SimHei
plt.rcParams['axes.unicode_minus'] = False #运行配置参数总的轴(axes)正常显示正负号(minus
# **********************************************************************播放量和收藏量数对比
# *******播放量条形图
fig, ax1 = plt.subplots()
plt.bar(dm_name, dm_play, color='cyan')
plt.title('播放量和收藏量数据分析')
plt.ylabel('播放量(万)')
ax1.tick_params(labelsize=6)
plt.xticks(rotation=90, color='green')

# *******收藏量折线图
ax2 = ax1.twinx() # 组合图必须加这个
ax2.plot(dm_favorite, color='green') # 设置线粗细,节点样式
plt.ylabel('收藏量(万)')
plt.plot(1, label='播放量', color="cyan", linewidth=5.0)
plt.plot(1, label='收藏量', color="green", linewidth=1.0, linestyle="-")
plt.legend()
plt.savefig(r'D:/爬虫测试/1.png', dpi=1000, bbox_inches='tight')

plt.show()


def main():
url = 'https://www.bilibili.com/v/popular/rank/bangumi' # 网址
html = get_html(url) # 获取返回值
# print(html)
info = save(html)
view(info)


if __name__ == '__main__':
main()

 

实验结果:

 

 

 

最后在putty上运行

putty运行过程:

1.putty登录

 

 

2.winscp登录和上传文件

 

 

 

 

3.putty下载库(调试环境)

      首先,我用的putty服务器类型属于linux,同时已经有了python3.7.2,大家可以先用python --version,测试自己的python版本,版本比较低的可以去下载

      对于我的代码中所用的库,如(re,bs4,matplotlib.pyplot,pandas等)可以用pip3 install  XXXX(这里输入你所用库的名字,例如:pip3 install Pandas)

      pip3 lists 可以检测自己当前所有的库(如下图)

 

 

下载好了库就尝试运行了,但是这里有个问题,代码中例如:‘D:/爬虫测试/Data1'等和自己电脑每个地址连接的地方,放入Winscp之后要重新在Winscp中重新新建这些文件,并更换成新的地址

 

最后进行代码得运行 python3 XXXXX.py(你所导入py文件的名字,例如我的就是 python3  pythonceshi.py)

运行结果如下:

 

 

 

   Winscp里面的新建的data1.txt 和 1.png也会和上面的运行结果一样,在此不再次作展示了,感兴趣的小伙伴们都可以拿去试试,如果哪里有不太好的地方,或者有更优化的方案,欢迎随时来找我讨论。

 

 

三、解析补充

1.库的介绍

re:正则表达式(英文名称:regular expression,regex,RE)是用来简洁表达一组字符串特征的表达式。最主要应用在字符串匹配中。

Pandas :  一个开放源码、BSD 许可的库,提供高性能、易于使用的数据结构和数据分析,式分析结构化数据的工具集,是 Numpy 库的一个子库,可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据。

openpyxl :是一个用于处理 xlsx 格式 Excel 表格文件的第三方 python 库,其支持 Excel 表格绝大多数基本操作。

Requests :  在 urllib 的基础上开发而来,它使用 Python 语言编写,并且采用了 Apache2 Licensed(一种开源协议)的 HTTP 库。用于网页的爬取。

BS4 :  Beautiful Soup 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库,它可以从 HTML 或 XML 文档中快速地提取指定的数据。

matplotlib.pyplot : 绘制各类可视化图形的命令子库,用户可通过调用pyplot使用Matplotlib中所有可视化的类.

2.代码的使用补充

  上面的代码分享,我已做了一部分批注,在这一块在对我认为可能有问题的地方进行一些介绍和补充

1).链接本机文件地址的问题

  with open('D:/爬虫测试/data1.txt', 'r+', encoding='UTF-8') as f:

  f.write(soup.text)

 

  plt.savefig(r'D:/爬虫测试/1.png', dpi=1000, bbox_inches='tight')

 

 

上面黄色部分,是你所保存爬取内容的文件,以及后续保存表格的地方,需要找到你电脑中该文件的位置,位置不固定,写对所放地址就好。


2).函数的介绍

 

 (1)

 def get_html(url):

 获取网页,对数据是否异常进行判断,获取网页编码方式

 (2)

 def save(html):


  先解析网页内容并进行保存,之后利用正则表达式(下面黄色内容)从中选择出所需的数据,进行打印并保存到excel表格中,例如:

 (3)

 js = re.search(r'\d*(\.)?\d', js).group()

(该部分有一个问题,如何从网页那么大量的信息中筛选出自己所需的那一部分数据,我在后面会简单介绍如何看网页的源代码。)
(4)

def view(info):

列出所用信息,并制作柱状图和折线图
dm_XXXX = info[Y]  

“XXXX”为你的数据起名字,Y对应着上面第Y-1个(和数组一样,从0开始)的info,也就是save中提取出来的字符串数组。
plt.bar(dm_name, dm_play, color='cyan')
plt.bar()里面是所调用的数据(如dm_name,dm_play),以及对应的颜色(color=‘’)。
plt.title()图表名字
plt.ylabel()图表纵坐标名字
plt.xlabel()图表横坐标名字


3)网站源代码的查看



 这样一大个源代码乍一看很猛,一堆字母不懂啊,别急首先我们先可以从英文单词下手。

head : 头部(网站顶部); body:身体(内容); foot:脚。

接着我们可以光标放在我们想知道的那行代码上,这时网页会对应显示这句代码的作用范围,如下图:

 

 

这样的话我们就可以一点一点找,找到如下内容,当然到这里有人会说,选中所要查的内容,直接F12,就可以查所选内容的源代码啊。

的确如此,但是,对于这个网页可能不是很方便,首先,我们所要查的内容都有链接,本人在操作时右键经常无法选中,而是就会被误判为点击链接,跳转至视频,相对麻烦。

而且接下去,还有一个”next_sibling“代码使用的原因,需要全代码才更好理解。

 

 

见上图,我用红色找出了所需要的数据,黄色找出了他们所对应区域的标签。

全文都是用div分割成一块一块,所以我们代码中就是先从带有div标签中寻找,然后class(我理解就是标签,class后面就可以放上我们黄色标签的内容)

于是:

(=>手工箭头的意思)

class_=’info‘     =>   动漫名字

class_=’detail‘  =>   动漫更新集数

class_=’detail-state‘     =>   动漫播放量和收藏量

  问题来了,动漫集数和收藏量在一起,如果不分开就会出现这样的结果

 

  大家就会发现第三部分明显包括了第四部分,所以这时候用了next_sibling,大家可以看第二张源代码图,收藏量在播放量下面的两行之外,于是我们就放入两个next_sibling,相当于将前面的播放量跳开,数据的搜集就会直接识别并保存收藏量了,这样就达到我们想要的结果了。

   4)知识点补充

      在进行该实验过程中,查到一些资料,有的以前上课提到过,有的是我这里库的使用,在此做一个补充,可供大家回顾和进一步修改该代码

 (1)文件读写操作:

    r: 以只读方式打开文件。文件的指针将会放在文件的开头。这是**默认模式**
    rb: 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
    r+: 打开一个文件用于读写。文件指针将会放在文件的开头。
    rb+:以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
    w: 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    wb: 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    w+: 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    wb+:以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    a: 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    ab: 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    a+: 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
    ab+:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

 (2)对于制作表格时的ax

   direction/tickdir : 可选{‘in’, ‘out’, ‘inout’}刻度线的方向
   size/length : float, 刻度线的长度
   width : float, 刻度线的宽度
   color : 刻度线的颜色,我一般用16进制字符串表示,eg:’#EE6363’
   labelsize : float/str, 刻度值字体大小
   labelcolor : 刻度值颜色

   plt.savefig()对图表进行保存

   plt.show()运行时运行图表,进行展示

 

 

(3)对于文件的处理

   f是flie的缩写,是对于文件的一个处理,以下还有其他使用方式的补充:

 

   file.read([size])   将文件数据作为字符串返回,可选参数size控制读取的字节数
file.readlines([size]) 返回文件中行内容的列表,size参数可选
file.write(str) 将字符串写入文件
file.writelines(strings) 将字符串序列写入文件
file.close() 关闭文件
file.closed 表示文件已经被关闭,否则为False
file.mode Access文件打开时使用的访问模式
file.encoding 文件所使用的编码
file.name 文件名
file.newlines 未读取到行分隔符时为None,只有一种行分隔符时为一个字符串,当文件有多种类型的行结束符时,则为一个包含所有当前所遇到的行结束的列表
file.softspace 为0表示在输出一数据后,要加上一个空格符,1表示不加。这个属性一般程序员用不着,由程序内部使用

 

 

 

 

 

四、实验过程中遇到的问题

 

问题一:最初 X-shell 没有下载成功

问题一解决办法:询问了老师,改用putty+Winscp

 

问题二:网页源代码不会看

问题二解决办法:自己打开了网页源代码,自己一点点尝试,最后发现了规律。

 

问题三:许多代码没见过,或者有的见过也不是很会用

问题三解决办法:自己一点点上网查,把源代码中包含的那一部分不断修改参数,删掉一部分等方式,观察输出结果的变化,一点点摸索代码的作用。

 

问题四:putty上环境调试有问题,运行指令不会。

问题四解决办法:询问同学时发现自己搞错了操作系统类型,自己申请的华为云ESC弹性服务器是linux,并且自身就已经是python3了,用的是yum而不是adt-get。

 

问题五:pandas库下载有问题,一直报错

问题五解决办法:在同学的帮助和上网查询下升级了自己的pip,然后就可以了。

 

问题六:源代码时间比较早,和当前有些出入

问题六解决办法:自己一点点尝试,一点点查,根据现在的网页界面进行修改。

 

五、个人感悟

   这是python课程的最后一次实验,这个实验的完成也代表着我的python修选课之旅可能要暂告一段落,内心其实还是感慨的。作为选修的python,相比于必修C语言而言,压力比较小,个人也比较享受学习python的过程,而且课程里安排的练手小程序很有意思,python的世界非常丰富多彩。课程结束了,课堂上王老师教的知识很多,或许我没能全部学会,有不少代码依旧不太会使用,但是我对python的兴趣越来越大。课程或许结束了,但是我在python世界里的探索或许才刚刚开始。 

   在本次python之旅种,我做了小学生计算题出题系统,然后是tk库界面设计的计算器,之后又是turtle库的国旗,玫瑰花,然后第一次尝试给别人的产品做测评,不久又是进行了通过python建立起来的局域网内加密通话,虽然我自己尝试的那个远远不及真正的交流软件,最后就是本次爬虫爬取信息做数据处理和可视化处理的实验。回顾这些实验的过程,或许实验的时候又很多很多不会,查资料查半天也可能没有查明白,程序不断的报错,但是现在我觉得都很值得的,因为在这个过程中我学到了许多东西,我做到了许多我曾经认为不可能的事。

   在此谢谢王志强老师的python课堂,每一节课都很有意思,没有想象中的刻板与严肃,而是活泼又有趣,少了一般课堂的死气沉沉,多了许多同学的好奇敲码。这一段时间真的很开心,很有趣,以后虽然课程结束了,但我依旧会继续在python的世界里继续遨游,做自己喜欢的程序,享受在python世界的快乐,最起码还有一个pygame的库还没有尝试过。

 

六、相关文献参考

 

https://www.php.cn/python-tutorials-423456.html

 

append 在python中什么意思

 

https://blog.csdn.net/Fwuyi/article/details/123084642

 

plt.rcParams[‘font.sans-serif‘] = [‘SimHei‘]

 

plt.rcParams[‘axes.unicode_minus‘] = False

 

https://blog.csdn.net/weixin_43360707/article/details/101034944

 

如何进行网页异常的判断

 

https://blog.csdn.net/Jacompol/article/details/111692298?ops_request_misc=&request_id=&biz_id=102&utm_term=python%E7%88%AC%E8%99%AB%E4%BB%A5%E5%8F%8A%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-111692298.142^v11^control,157^v12^new_style&spm=1018.2226.3001.4187

源代码

 

https://www.bilibili.com/v/popular/rank/bangumi

爬取的网站

 

https://blog.csdn.net/A78562/article/details/119678326

linux环境pip更新命令

 

posted @ 2022-05-29 08:48  张家有子名若尘  阅读(97)  评论(0编辑  收藏  举报