2203840423邓佳湧python期末作业

【python爬虫课程设计】博物馆数据爬取+可视化

选题背景介绍

博物馆网络爬虫的选题背景源于对文化遗产数字化管理的需求。随着互联网的普及,越来越多的博物馆将其藏品信息、展览信息等发布在官网上,这些信息对于研究者、策展人、教育者等都具有很高的价值。为了更高效地收集、整理这些信息,同时避免手工整理的繁琐与错误,博物馆网络爬虫应运而生。它能够自动抓取博物馆网站上的信息,并按照一定的格式整理成数据,为博物馆的数字化建设提供有力支持。因此,博物馆网络爬虫的选题背景与文化遗产数字化管理的趋势紧密相关,是信息技术与文化遗产保护相结合的产物。

选题意义

数据整合与共享:通过博物馆网络爬虫,可以将分散在各个博物馆网站上的信息进行整合,形成一个庞大的数据库,方便研究者、策展人、教育者等用户进行数据查询、分析和利用。这有助于促进文化遗产的共享与传播,提高文化资源的利用效率。

学术研究支持:博物馆网络爬虫能够抓取博物馆网站上的文物信息、展览信息等,为学术研究提供丰富的数据支持。通过分析这些数据,可以深入挖掘文化遗产的历史价值、艺术价值、科学价值等,推动学术研究的深入发展。

数字化管理助力:博物馆网络爬虫的应用有助于推动博物馆的数字化管理进程。通过自动化的数据采集和整理,可以减轻博物馆工作人员的工作负担,提高工作效率。同时,数字化管理有助于保护文化遗产,减少文物损坏和遗失的风险。

促进跨学科合作:博物馆网络爬虫的研发和应用涉及多个学科领域,如计算机科学、历史学、艺术学等。这种跨学科的合作有助于推动不同领域之间的交流与融合,促进学科创新与发展。

HTML页面解析

QQ图片20231226181832

爬虫流程介绍

目标网站

https://www.kfsbwg.com/#/collectionSelection

目标信息

博物馆藏品数据

工具库

requests库,json库,BeautifulSoup库,pandas库,matplotlib库

通过模拟浏览器发送请求,并解析返回的数据。代码分为以下几个步骤:

  1. 设置伪装的请求头信息,包括 User-Agent(浏览器名称)、Referer(来源页面地址)和 Cookie。

2. 使用伪装的请求头发送 GET 请求,获取网页内容并解析。

# 发送 GET 请求,使用伪装的请求头信息

res = requests.get('https://www.kfsbwg.com/#/collectionSelection', headers=fake_headers) # 添加headers参数

# 使用 XPath 解析返回的网页内容

xpath_data = etree.HTML(res.text)

3. 提取网页中的类别信息。

categories_div = xpath_data.xpath('//div[contains(@class,"tab")]')

# 使用 XPath 根据特定规则提取包含类别信息的 `<div>` 元素。

4. 遍历多个页面,获取每个页面的数据,并将数据存储到 DataFrame 中。

(1) 该代码片段遍历了页码 1 到 13, 爬取藏品的基本信息。创建一个空的 DataFrame,用于存储数据。

  1. 该代码片段对进入二级页面,爬取每一个藏品的类别信息

  1. 保存数据到本地文件。

爬虫程序设计

Part1: 爬取博物馆里的数据并保存为“collect_data”文件

111

222444

Part2: 各个年代的藏品数量的折线图

Part3: 各个年代的藏品数量的折线图

Part4:文物级别的数量 绘制条形图

Part5: 一级文物中 按类别 画环形图

Part6: 对藏品介绍绘制词云图

爬虫程序设计全部代码如下:

  1. import requests # 用来爬虫
  2. import json
  3. import matplotlib.pyplot as plt
  4. from lxml import etree
  5. import re
  6. import pandas as pd
  7. import jieba #分词库
  8. from wordcloud import WordCloud #词云库
  9. # 读取停用词列表
  10. def get_stopword_list(file):
  11. with open(file, 'r', encoding='utf-8') as f: # 打开停用词列表文件,使用utf-8编码
  12. stopword_list = [word.strip('\n') for word in f.readlines()] # 逐行读取文件内容,去除换行符并添加到停用词列表中
  13. return stopword_list
  14. def crawling():
  15. # 设置伪装的请求头信息,包括 User-Agent(浏览器名称)、Referer(来源页面地址)和 Cookie。伪装成浏览器
  16. cookie = 'gr_user_id=d60a8db5-dbfc-44f3-a589-6917209bca37; douban-fav-remind=1; ' \
  17. '_vwo_uuid_v2=D5FD64F0F6B348BAC2D886383CA278542|628badf33068a364065510f6d407970d; ' \
  18. 'bid=mAIlAppZr5U; ll="118284"; __utmz=30149280.1685770417.9.3.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; ' \
  19. '__utma=30149280.678090237.1611223142.1685770417.1685867065.10; __utma=223695111.1624638446.1617981352.1658030776.1685867065.3; ' \
  20. '__utmz=223695111.1685867065.3.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __yadk_uid=NnfgVqOPYabVP9s7AkUc0PpTGwjICPYJ; ' \
  21. '_pk_id.100001.4cf6=90c321bacf3d595a.1685867070.; ' \
  22. '__gads=ID=8d4773a0f5c6d0bb-2268ff2418dd009b:T=1680945664:RT=1685867186:S=ALNI_MYgy1qlxmUrwLO53cc5XfkdoSLdcw; ' \
  23. '__gpi=UID=0000069a7ea9078e:T=1655104213:RT=1685867186:S=ALNI_MakTxIc3yRNFn3nppio26xG6RXfEA; ' \
  24. '_pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1686124106%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D; ' \
  25. '_pk_ses.100001.4cf6=1; ap_v=0,6.0'
  26. fake_headers = {
  27. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36', #浏览器名称
  28. 'Referer': 'https://www.kfsbwg.com/#/home', #来源页面的地址
  29. 'Cookie': cookie #cookie
  30. }
  31. # 发送 GET 请求,使用伪装的请求头信息
  32. res = requests.get('https://www.kfsbwg.com/#/collectionSelection', headers=fake_headers) # 添加headers参数
  33. # 使用 XPath 解析返回的网页内容
  34. xpath_data = etree.HTML(res.text)
  35. #代理ip全局参数
  36. ip = "" # 请求时使用的ip值
  37. # 代理ip列表,来自免费代理ip网站
  38. # 通过代理ip爬虫防止被封禁
  39. # 去除停用词
  40. stopwords = STOPWORDS
  41. # stopwords.add('')
  42. #代理ip全局参数
  43. ip = "" # 请求时使用的ip值
  44. # 代理ip列表,来自免费代理ip网站
  45. # 通过代理ip爬虫防止被封禁
  46. agency_ip = [
  47. 'http://49.86.58.36:9999',
  48. 'http://182.84.144.91:3256',
  49. 'http://171.35.213.44:9999',
  50. 'http://114.67.108.243:8081',
  51. 'http://211.24.95.49:47615',
  52. 'http://192.168.110.254:8088'
  53. ]
  54. proxies = {'http': 'http://192.168.110.254:8088'}
  55. # 提取类别: 使用 XPath 根据特定规则提取包含类别信息的 `<div>` 元素。
  56. categories_div = xpath_data.xpath('//div[contains(@class,"tab")]')
  57. pages = range(1,14) #遍历页码范围,该代码片段遍历了页码 1 到 13。
  58. data = pd.DataFrame(columns=['藏品名称' ,'年代' ,'类别','文物级别' ,'尺寸描述' ,'长' ,'宽' ,'高' ,'介绍' ]) # 创建一个空的 DataFrame,用于存储数据
  59. for page in pages: #循环遍历每一页。
  60. # 循环每一页。一页12个。url是找到的数据接口api。 该网站数据是从接口动态获取的,不能靠爬取网页获得信息。
  61. url = "https://www.kfsbwg.com/api/exhibit/list?p=w&qu_id=0&is_home=2&page="+str(page)+"&limit=12" # 构建请求 URL,该 URL 包含页码等参数
  62. # 请求数据:# 构建请求 URL,并发送 GET 请求
  63. response = requests.get(url, headers=fake_headers) # 发送 GET 请求,使用伪装的请求头信息
  64. content = response.content # 将获取到的二进制数据转换为 UTF-8 字符串。
  65. text = content.decode('utf-8')
  66. # 将获取的数据解析成json对象,解析返回的 JSON 数据,并遍历每个数据项
  67. json_object = json.loads(text)
  68. #解析返回的 JSON 数据,将其转换为 Python 对象。
  69. collect_list = json_object["data"]["list"] #从 JSON 对象中获取数据列表。
  70. # 当前页藏品数据数量
  71. len_ = len(collect_list)
  72. print("数据长度:"+str(len_))
  73. # 遍历每个数据项,并提取所需的字段信息
  74. for collect in collect_list:
  75. exhibit_id = collect['exhibit_id'] # id
  76. print("爬取:exhibit_id:" + str(exhibit_id))
  77. name = collect['exhibit_name'] # 藏品名称
  78. print("爬取:exhibit_name:" + str(name))
  79. year = collect['year'] # 年份
  80. print("爬取:year:" + str(year))
  81. leve = collect['leve'] # 等级
  82. print("爬取:leve:" + str(leve))
  83. size_desc = collect['size_desc'] # 尺寸
  84. print("爬取:size_desc:" + str(size_desc))
  85. length = collect['length'] # 长
  86. print("爬取:length:" + str(length))
  87. width = collect['width'] # 宽
  88. print("爬取:width:" + str(width))
  89. height = collect['height'] # 高
  90. print("爬取:height:" + str(height))
  91. intro = collect['intro'] # 介绍
  92. print("爬取:intro:" + str(intro))
  93. # 前往二级接口(文物详情)爬取类别信息,并解析返回的数据
  94. sub_url = "https://www.kfsbwg.com/api/exhibit/detail?p=w&exhibit_id="
  95. # 构建二级接口的请求 URL,根据展品 ID 获取展品详情
  96. sub_url = sub_url + str(exhibit_id)
  97. # 请求数据
  98. sub_response = requests.get(sub_url, headers=fake_headers) # 发送 GET 请求,使用伪装的请求头信息
  99. content = sub_response.content
  100. text = content.decode('utf-8')
  101. # 将获取的数据解析成json对象
  102. sub_json_object = json.loads(text)
  103. # 从 JSON 对象中获取类型信息
  104. cate_name = sub_json_object["data"]["cate_name"]
  105. # '藏品名称' ,'年代' ,'类别','文物级别' ,'尺寸描述' ,'长' ,'宽' ,'高' ,'介绍'
  106. data.loc[len(data)] = [name,year,cate_name,leve,size_desc,length,width, height,intro] # 将提取的数据存储到 DataFrame 中
  107. print('藏品名称: %s ,年代: %s ,类别: %s ,文物级别: %s ,尺寸描述: %s ,长: %s ,宽: %s ,高: %s ,介绍: %s '
  108. %(name,year,cate_name,leve,size_desc,length,width, height,(intro[:10]+'...')))
  109. print("一共爬取:" + str(len(data)) + "行藏品数据信息")
  110. # 保存数据
  111. data.to_csv('./collect_data.csv',encoding='utf-8')
  112. '''
  113. 1. 按年代分组 数量:折线图
  114. 2. 按类别分组,扇形图
  115. 3. 按文物级别,条形图
  116. 4. 一级文物中朝代 柱状图
  117. 5. 一级文物中类别 多柱状图
  118. 6. 文物描述 词云图
  119. '''
  120. # 1. 各个年代的藏品数量的折线图
  121. def plot1():
  122. print("准备绘制图1:各个年代的藏品数量的折线图")
  123. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  124. '''读取数据'''
  125. collectData = pd.read_csv('./collect_data.csv')
  126. # 年代按顺序排序:
  127. yearSet = ['新石器时代','商','西周', '春秋','战国','秦', '汉', '三国','东晋', '南北朝', '北魏', '东魏',
  128. '隋','唐','五代十国','宋','北宋','南宋','辽', '金','元', '明', '清', '民国','其他']
  129. group = collectData.groupby(by='年代') # 数据按年代分组
  130. yearNum = []
  131. for i in range(0,len(yearSet)):
  132. yearCollect = group.get_group(yearSet[i])
  133. yearNum.append(len(yearCollect))
  134. # 横坐标数据
  135. X = range(0,len(yearSet))
  136. fig = plt.figure(figsize=(12, 4)) # 绘图大小
  137. subfig = plt.subplot(1, 1, 1) # 子图对象
  138. subfig.plot(X, yearNum, '-*', color='lightgreen', linewidth=2, markersize='8')
  139. plt.xticks(X, yearSet,rotation=40)
  140. for a, b in zip(X, yearNum):
  141. '''在数据点上进行标注'''
  142. plt.text(a, b+2, b, ha='center', va='bottom')
  143. # 纵竖线
  144. subfig.set_ylim((0, 50))
  145. subfig.set_xlabel(r'年代')
  146. subfig.set_ylabel(r'数量')
  147. subfig.set_title('不同年代的藏品数量统计')
  148. plt.tight_layout()
  149. plt.savefig('./不同年代的藏品数量统计.png')
  150. plt.show()
  151. “针对藏品进行分类”
  152. # 2. 各个类型的藏品数量的扇形图
  153. def plot2():
  154. print("准备绘制图2:各个类型的藏品数量的扇形图")
  155. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  156. '''读取数据'''
  157. collectData = pd.read_csv('./collect_data.csv')
  158. group = collectData.groupby(by='类别') # 数据按类别分组
  159. i = 0
  160. cate_list = set(list(collectData['类别'])) # 获取一共有哪些类别
  161. cate_count = list(range(0,len(cate_list)))
  162. for a_cate in cate_list:
  163. cate_df = group.get_group(a_cate)
  164. # 类别数量
  165. cate_count[i] = len(cate_df)
  166. i += 1
  167. fig = plt.figure(figsize=(8, 6))
  168. subfig = plt.subplot(1, 1, 1)
  169. subfig.pie(cate_count, labels=cate_list, autopct='%.1f%%')
  170. subfig.set_title('各类别的藏品数量扇形图')
  171. subfig.set_ylabel('')
  172. plt.savefig('./各类别的藏品数量扇形图.png')
  173. plt.show()
  174. “针对文物进行分类”
  175. # 3. 文物级别的数量 绘制条形图
  176. def plot3():
  177. print("准备绘制图3:文物级别的数量条形图")
  178. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  179. '''读取数据'''
  180. collectData = pd.read_csv('./collect_data.csv')
  181. group = collectData.groupby(by='文物级别') # 数据按文物级别分组
  182. i = 0
  183. level_list = set(list(collectData['文物级别'])) # 获取一共有几级文物级别
  184. level_count = list(range(0, len(level_list)))
  185. for a_level in level_list: # 循环每个等级
  186. level_df = group.get_group(a_level)
  187. # 等级数量
  188. level_count[i] = len(level_df)
  189. i += 1
  190. fig = plt.figure(figsize=(8, 4))
  191. subfig = plt.subplot(1, 1, 1)
  192. y = list(range(len(level_list)))
  193. subfig.barh(y, level_count, height=0.5)
  194. subfig.set_xlabel('个')
  195. subfig.set_title('不同文物级别的藏品数量')
  196. plt.legend()
  197. plt.yticks(y, level_list)
  198. for a, b in zip(level_count,y):
  199. '''标注数据'''
  200. “并且对数据进行分类”
  201. plt.text(a+2, b, a, ha='center', va='bottom')
  202. plt.savefig('./不同文物级别的藏品数量.png')
  203. plt.show()
  204. “针对一级文物进行分类”
  205. # 4. 筛选出一级文物,统计一级文物里各个朝代的文物数量
  206. def plot4():
  207. print("准备绘制图4:统计一级文物里各个朝代的文物数量")
  208. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  209. '''读取数据'''
  210. collectData = pd.read_csv('./collect_data.csv')
  211. group = collectData.groupby(by='文物级别') # 数据按文物级别分组
  212. level_1 = group.get_group('一级文物') # 获取一级文物的数据(DataFrame)
  213. group = level_1.groupby(by='年代') # 将一级文物的数据按年代分组
  214. i = 0
  215. year_list = set(list(level_1['年代'])) # 获取一共有哪些朝代
  216. year_count = list(range(0, len(year_list))) # 列表放每个朝代的藏品数量
  217. for a_year in year_list:
  218. year_df = group.get_group(a_year)
  219. # 类别数量
  220. year_count[i] = len(year_df)
  221. i += 1
  222. x = list(range(0, len(year_list)))
  223. fig = plt.figure(figsize=(10, 8))
  224. subfig = plt.subplot(1, 1, 1)
  225. subfig.bar(x, year_count,color='lightgreen')
  226. for a, b in zip(x,year_count):
  227. '''标注数据'''
  228. plt.text(a, b+0.1, b, ha='center', va='bottom')
  229. subfig.set_ylim((0, 5.5))
  230. plt.xticks(x, year_list) # rotation=-50
  231. subfig.set_ylabel(r'藏品数量')
  232. subfig.set_title('一级文物中来自各个朝代的藏品的数量')
  233. plt.savefig('./一级文物中来自各个朝代的藏品的数量.png')
  234. plt.show()
  235. “针对一级文物进行分类”
  236. # 5.一级文物中 按类别 画环形图
  237. def plot5():
  238. print("准备绘制图5:统计一级文物里各个类别的文物数量环形图")
  239. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  240. '''读取数据'''
  241. collectData = pd.read_csv('./collect_data.csv')
  242. group = collectData.groupby(by='文物级别') # 数据按文物级别分组
  243. level_1 = group.get_group('一级文物') # 获取一级文物的数据(DataFrame)
  244. group = level_1.groupby(by='类别') # 将一级文物的数据按年代分组
  245. i = 0
  246. cate_list = set(list(level_1['类别'])) # 获取一共有哪些朝代
  247. cate_count = list(range(0, len(cate_list))) # 列表放每个朝代的藏品数量
  248. for a_cate in cate_list:
  249. cate_df = group.get_group(a_cate)
  250. # 类别数量
  251. cate_count[i] = len(cate_df)
  252. i += 1
  253. x = list(range(0, len(cate_list)))
  254. fig = plt.figure(figsize=(7, 7))
  255. subfig = plt.subplot(1, 1, 1)
  256. # 要把离心率设置远一点,怕第二个饼图挡住这个百分率
  257. subfig.pie(cate_count, pctdistance=0.8, autopct='%.1f%%')
  258. # 所谓的环形图,就是再画一个比上个图小的饼图,并且为白色,所以半径要小
  259. subfig.pie([1], radius=0.6, colors='w')
  260. subfig.legend(cate_list, loc='upper left')
  261. subfig.set_title('一级文物中各个类别的藏品的占比')
  262. plt.savefig('./一级文物中各个类别的藏品的占比.png')
  263. plt.show()
  264. ## 6. 对藏品介绍绘制词云图
  265. def plot6():
  266. print("准备绘制图6:对藏品介绍绘制词云图")
  267. plt.rcParams['font.sans-serif'] = ['Simhei'] # 显示中文
  268. '''读取数据'''
  269. collectData = pd.read_csv('./collect_data.csv')
  270. intro = list(collectData['介绍'])
  271. new_text = []
  272. all_text = ''
  273. for str in intro:
  274. # 去除无用的标点符号,分词和预处理
  275. remove_chars = '[brp·’!"\#$%&\'()#!()*+,-./:;<=>?\@,:。?¥★、….>【】[]《》?“”‘’\[\\]^_`{|}~]+'
  276. str = re.sub(remove_chars, "", str)
  277. str.replace('br', '').replace('p', '')
  278. result = jieba.cut(str)
  279. a = ','.join(result).split(',')
  280. new_text.append(a)
  281. # 去除停用词
  282. stopwords = get_stopword_list('stopwords.txt') # 获取停用词列表,加载停用词的路径为'stopwords.txt'
  283. stopwords.append('厘米') # 添加额外的停用词
  284. stopwords.append('这件')
  285. stopwords.append('')
  286. for s in new_text:
  287. for word in s:
  288. if word not in stopwords: # 判断分词后的词语是否在停用词表内
  289. if word != '\t' and len(word) > 1: # 去除空字符和长度小于2的词语
  290. all_text += word + ' ' # 拼接所有分词后的词语
  291. # 词云图
  292. font = "C:\\Windows\\Fonts\\simsun.ttc" # 词云的中文字体所在路径
  293. wc = WordCloud(
  294. scale=4, # 调整图片大小---(如果设置太小图会很模糊)
  295. font_path=font, # 使用的字体库
  296. max_words=300, # 词云显示的最大词数
  297. margin=1, # 字体之间的间距
  298. background_color='white', # 背景颜色
  299. max_font_size=60,
  300. # min_font_size=1,
  301. # stopwords=STOPWORDS, #屏蔽的内容
  302. collocations=True, # 避免重复单词
  303. # width=1600, height=1200 # 图像宽高,字间距
  304. )
  305. wc.generate(all_text)
  306. wc.to_file('词云图.jpg') # 保存到当地文件
  307. if __name__ == '__main__':
  308. crawling()
  309. plot1()
  310. plot2()
  311. plot3()
  312. plot4()
  313. plot5()
  314. plot6()

总结:

博物馆网络爬虫与数据可视化相结合,为文化遗产的数字化管理提供了有力支持。通过博物馆网络爬虫,实现对博物馆网站数据的自动抓取和整理,形成结构化的数据集。数据可视化则将这些数据以直观、生动的方式呈现出来,便于用户理解和分析。这种结合不仅提高了数据处理的效率和准确性,还为用户提供了更加丰富和深入的洞察力。通过数据可视化,用户可以快速识别数据中的模式、趋势和关联,进一步挖掘文化遗产的价值。这种技术有助于推动学术研究的进步,促进跨学科的合作,同时也为公众提供了更加便捷的文化资源访问途径。

posted @   丁丁0118  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示