任务描述

本次实践使用Python来爬取百度百科中《乘风破浪的姐姐》所有选手的信息,并进行可视化分析。

数据获取:https://baike.baidu.com/item/乘风破浪的姐姐

上网的全过程:

普通用户:打开浏览器 --> 往目标站点发送请求 --> 接收响应数据 --> 渲染到页面上。爬虫程序:模拟浏览器 --> 往目标站点发送请求 --> 接收响应数据 --> 提取有用的数据 --> 保存到本地/数据库。

爬虫的过程

1.发送请求(requests模块)2.获取响应数据(服务器返回)3.解析并提取数据(BeautifulSoup查找或者re正则)4.保存数据

本实践中将会使用以下两个模块,首先对这两个模块简单了解以下:

request模块:

requests是python实现的简单易用的HTTP库,官网地址:http://cn.python-requests.org/zh_CN/latest/requests.get(url)可以发送一个http get请求,返回服务器响应内容。

BeautifulSoup库:

BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。网址:https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml。BeautifulSoup(markup, "html.parser")或者BeautifulSoup(markup, "lxml"),推荐使用lxml作为解析器,因为效率更高。

数据爬取

一、爬取百度百科中《乘风破浪的姐姐》中所有参赛嘉宾信息,返回页面数据

爬取的是图中的表格信息:

import json
import re
import requests
import datetime
from bs4 import BeautifulSoup
import osdef crawl_wiki_data():"""爬取百度百科中《乘风破浪的姐姐》中嘉宾信息,返回html"""headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}url='https://baike.baidu.com/item/乘风破浪的姐姐'                         try:response = requests.get(url,headers=headers)#将一段文档传入BeautifulSoup的构造方法,就能得到一个文档的对象, 可以传入一段字符串soup = BeautifulSoup(response.text,'html.parser')     #返回所有的<table>所有标签tables = soup.find_all('table')crawl_table_title = "按姓氏首字母排序"for table in  tables:           #对当前节点前面的标签和字符串进行查找table_titles = table.find_previous('div')for title in table_titles:if(crawl_table_title in title):return table       except Exception as e:print(e)

返回html文件。

二、对爬取的参赛嘉宾页面数据进行解析,并保存为JSON文件

def parse_wiki_data(table_html):'''解析得到选手信息,包括包括选手姓名和选手个人百度百科页面链接,存JSON文件,保存到work目录下'''bs = BeautifulSoup(str(table_html),'html.parser')all_trs = bs.find_all('tr')stars = []for tr in all_trs:all_tds = tr.find_all('td')   #tr下面所有的td          for td in  all_tds:#star存储选手信息,包括选手姓名和选手个人百度百科页面链接star = {}    if td.find('a'):#找选手名称和选手百度百科连接if td.find_next('a'):star["name"]=td.find_next('a').textstar['link'] =  'https://baike.baidu.com' + td.find_next('a').get('href')elif td.find_next('div'):star["name"]=td.find_next('div').find('a').textstar['link'] = 'https://baike.baidu.com' + td.find_next('div').find('a').get('href')stars.append(star)json_data = json.loads(str(stars).replace("\'","\""))   with open('work/' + 'stars.json', 'w', encoding='UTF-8') as f:json.dump(json_data, f, ensure_ascii=False)

需要在代码文件目录中新建“work”文件夹:

三、爬取每个选手的百度百科页面的信息,并进行保存

  • 这里可以查看网页源代码(F12),查看需要爬取的信息所处的html标签,不同网页使用的标签和属性都不同,要灵活变通。
  • 如这里百度百科图片的爬取,有些选手的百科网页上的图片所在标签为类summary-pic,有的为类lemma-album,本文通过分支语句实现正确爬取。
def crawl_everyone_wiki_urls():#爬取每个选手的百度百科图片,并保存with open('work/' + 'stars.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' }  star_infos = []for star in json_array:star_info = {}       name = star['name']link = star['link']star_info['name'] = name#向选手个人百度百科发送一个http get请求response = requests.get(link,headers=headers)        #将一段文档传入BeautifulSoup的构造方法,就能得到一个文档的对象bs = BeautifulSoup(response.text,'html.parser')       #获取选手的民族、星座、血型、体重等信息base_info_div = bs.find('div',{'class':'basic-info cmn-clearfix'})dls = base_info_div.find_all('dl')for dl in dls:dts = dl.find_all('dt')for dt in dts:if "".join(str(dt.text).split()) == '民族':star_info['nation'] = dt.find_next('dd').textif "".join(str(dt.text).split()) == '星座':star_info['constellation'] = dt.find_next('dd').textif "".join(str(dt.text).split()) == '血型':  star_info['blood_type'] = dt.find_next('dd').textif "".join(str(dt.text).split()) == '身高':  height_str = str(dt.find_next('dd').text)star_info['height'] = str(height_str[0:height_str.rfind('cm')]).replace("\n","")if "".join(str(dt.text).split()) == '体重':  star_info['weight'] = str(dt.find_next('dd').text).replace("\n","")if "".join(str(dt.text).split()) == '出生日期':  birth_day_str = str(dt.find_next('dd').text).replace("\n","")if '年' in  birth_day_str:star_info['birth_day'] = birth_day_str[0:birth_day_str.rfind('年')]star_infos.append(star_info) #========================NOTICE===========================  # 从个人百度百科页面中解析得到一个链接,该链接指向选手图片列表页面# 百度百科的网页分为两版:1、summary-pic;2、lemma-album。这里分两种情况爬取图片  if bs.select('.summary-pic a'):pic_list_url = bs.select('.summary-pic a')[0].get('href')pic_list_url = 'https://baike.baidu.com' + pic_list_urlelif bs.select('.lemma-album'):pic_list_url = bs.select('.lemma-album')[0].get('href')pic_list_url = 'https://baike.baidu.com' + pic_list_url#========================NOTICE=========================== #向选手图片列表页面发送http get请求pic_list_response = requests.get(pic_list_url,headers=headers)#对选手图片列表页面进行解析,获取所有图片链接bs = BeautifulSoup(pic_list_response.text,'html.parser')pic_list_html=bs.select('.pic-list img ')pic_urls = []for pic_html in pic_list_html: pic_url = pic_html.get('src')pic_urls.append(pic_url)#根据图片链接列表pic_urls, 下载所有图片,保存在以name命名的文件夹中down_save_pic(name,pic_urls)#将个人信息存储到json文件中json_data = json.loads(str(star_infos).replace("\'","\""))   with open('work/' + 'stars_info.json', 'w', encoding='UTF-8') as f:json.dump(json_data, f, ensure_ascii=False)
def down_save_pic(name,pic_urls):'''根据图片链接列表pic_urls, 下载所有图片,保存在以name命名的文件夹中,'''path = 'work/'+'pics/'+name+'/'if not os.path.exists(path):os.makedirs(path)for i, pic_url in enumerate(pic_urls):try:pic = requests.get(pic_url, timeout=15)string = str(i + 1) + '.jpg'with open(path+string, 'wb') as f:f.write(pic.content)#print('成功下载第%s张图片: %s' % (str(i + 1), str(pic_url)))except Exception as e:#print('下载第%s张图片时失败: %s' % (str(i + 1), str(pic_url)))print(e)continue

爬取保存的选手图片,按照名字作为文件夹名字:

四、数据爬取主程序

if __name__ == '__main__':#爬取百度百科中《乘风破浪的姐姐》中参赛选手信息,返回htmlhtml = crawl_wiki_data()#解析html,得到选手信息,保存为json文件parse_wiki_data(html)#从每个选手的百度百科页面上爬取,并保存crawl_everyone_wiki_urls()print("所有信息爬取完成!")

数据分析

一、绘制选手年龄分布柱状图

import matplotlib.pyplot as plt
import numpy as np
import json
import matplotlib.font_manager as font_manager
#显示matplotlib生成的图形
%matplotlib inlinewith open('work/stars_info.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())#绘制选手年龄分布柱状图,x轴为年龄,y轴为该年龄的小姐姐数量
birth_days = []
for star in json_array:if 'birth_day' in dict(star).keys():birth_day = star['birth_day'] if len(birth_day) == 4:  birth_days.append(birth_day)birth_days.sort()
print(birth_days)birth_days_list = []
count_list = []for birth_day in birth_days:if birth_day not in birth_days_list:count = birth_days.count(birth_day)birth_days_list.append(birth_day)count_list.append(count)print(birth_days_list)
print(count_list)# 设置显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.figure(figsize=(15,8))
plt.bar(range(len(count_list)), count_list,color='r',tick_label=birth_days_list,facecolor='#9999ff',edgecolor='white')# 这里是调节横坐标的倾斜度,rotation是度数,以及设置刻度字体大小
plt.xticks(rotation=45,fontsize=20)
plt.yticks(fontsize=20)plt.legend()
plt.title('''《乘风破浪的姐姐》参赛嘉宾''',fontsize = 24)
plt.savefig('/home/aistudio/work/result/bar_result01.jpg')
plt.show()


或者:

import numpy as np
import json
import matplotlib.font_manager as font_manager
import pandas as pd
#显示matplotlib生成的图形
%matplotlib inlinedf = pd.read_json('work/stars_info.json',dtype = {'birth_day' : str})
#print(df)
df = df[df['birth_day'].map(len) == 4]
#print(df)grouped=df['name'].groupby(df['birth_day'])
#print(grouped)
s = grouped.count()
birth_days_list = s.index
count_list = s.values# 设置显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.figure(figsize=(15,8))
plt.bar(range(len(count_list)), count_list,color='r',tick_label=birth_days_list,facecolor='#9999ff',edgecolor='white')
# 这里是调节横坐标的倾斜度,rotation是度数,以及设置刻度字体大小
plt.xticks(rotation=45,fontsize=20)
plt.yticks(fontsize=20)
# plt.legend()
plt.title('''《乘风破浪的姐姐》参赛嘉宾''',fontsize = 24)
plt.savefig('/home/aistudio/work/bar_result02.jpg')
plt.show()

二、绘制选手体重饼状图

import matplotlib.pyplot as plt
import numpy as np
import json
import matplotlib.font_manager as font_manager
#显示matplotlib生成的图形
%matplotlib inlinewith open('work/stars_info.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())#绘制选手体重分布饼状图
weights = []
counts = []for star in json_array:if 'weight' in dict(star).keys():weight = float(star['weight'][0:2])weights.append(weight)
print(weights)size_list = []
count_list = []size1 = 0
size2 = 0
size3 = 0
size4 = 0for weight in weights:if weight <=45:size1 += 1elif 45 < weight <= 50:size2 += 1elif 50 < weight <= 55:size3 += 1else:size4 += 1labels = '<=45kg', '45~50kg', '50~55kg', '>55kg'sizes = [size1, size2, size3, size4]
explode = (0.2, 0.1, 0, 0)
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',shadow=True)
ax1.axis('equal')
plt.savefig('/home/aistudio/work/pie_result01.jpg')
plt.show()


import matplotlib.pyplot as plt
import numpy as np
import json
import matplotlib.font_manager as font_manager
import pandas as pd
#显示matplotlib生成的图形
%matplotlib inlinedf = pd.read_json('work/stars_info.json')
#print(df)
weights=df['weight']
arrs = weights.valuesarrs = [x for x in arrs if not pd.isnull(x)]
for i in range(len(arrs)):   arrs[i] = float(arrs[i][0:2])#pandas.cut用来把一组数据分割成离散的区间。比如有一组年龄数据,可以使用pandas.cut将年龄数据分割成不同的年龄段并打上标签。bins是被切割后的区间.
bin=[0,45,50,55,100]
se1=pd.cut(arrs,bin)
#print(se1)#pandas的value_counts()函数可以对Series里面的每个值进行计数并且排序。sizes = pd.value_counts(se1)
print(sizes)
labels = '45~50kg', '<=45kg','50~55kg', '>55kg'
explode = (0.2, 0.1, 0, 0)  fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',shadow=True, startangle=90)
ax1.axis('equal')
plt.savefig('/home/aistudio/work/pie_result02.jpg')
plt.show()

三、作业:绘制选手身高饼状图

### 此处写绘制选手身高饼图的代码
import matplotlib.pyplot as plt
import numpy as np
import json
import matplotlib.font_manager as font_manager
#显示matplotlib生成的图形
# %matplotlib inlinewith open('work/stars_info.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())#绘制选手身高分布饼状图
heights = []
counts = []for star in json_array:if 'height' in dict(star).keys():height = float(star['height'][0:3])heights.append(height)
print(heights)size_list = []
count_list = []size1 = 0
size2 = 0
size3 = 0
size4 = 0for height in heights:if height <=160:size1 += 1elif 160 < height <= 165:size2 += 1elif 165 < height <= 170:size3 += 1else:size4 += 1labels = '<=160cm', '160~165cm', '165~170cm', '>170cm'
# print(sizes)
sizes = [size1, size2, size3, size4]
explode = (0.2, 0.1, 0, 0.1)
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%')
ax1.axis('equal')
plt.savefig('work/result/pie_height_result01.jpg')
plt.show()

四、作业:绘制选手身高和体重的散点图,并对其相关关系进行分析

### 此处写绘制选手身高和体重散点图的代码
import matplotlib.pyplot as plt
import jsonwith open('work/stars_info.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())heights = []
weights = []for star in json_array:if 'height' in dict(star).keys() and 'weight' in dict(star).keys():height = float(star['height'][0:3])heights.append(height)weight = float(star['weight'][0:2])weights.append((weight))
# print(heights, weights)
plt.scatter(heights, weights, marker="o")
plt.axis()# plt.rcParams['font.sa ns-serif'] = ['SimHei'] # 指定默认字体
plt.title("身高体重散点图")
plt.xlabel("身高(cm)")
plt.ylabel("体重(kg)")
plt.show()

五、作业:自由根据数据集对该数据集进行可视化分析,有新颖分析视角及有价值的分析结论的同学会有加分

  • 这里在同一figure中显示多个图片,使用subplot(row, col, index)。
  • 注意subplot()要在生成图片的语句之前。
import matplotlib.pyplot as plt
import jsonwith open('work/stars_info.json', 'r', encoding='UTF-8') as file:json_array = json.loads(file.read())heights = []
births = []
bloods = []for star in json_array:if 'height' in dict(star).keys() and 'birth_day' in dict(star).keys() and star['birth_day'][0] == '1':height = float(star['height'][0:3])heights.append(height)birth = float(star['birth_day'][0:4])births.append(2020 - birth)
# print(heights, weights)
plt.subplot(1, 2, 1)
plt.scatter(births, heights, marker="o")
plt.axis()plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.title("身高-年龄散点图")
plt.xlabel("年龄(岁)")
plt.ylabel("身高(cm)")
# plt.show()heights = []
for star in json_array:if 'height' in dict(star).keys() and 'blood_type' in dict(star).keys():height = float(star['height'][0:3])heights.append(height)blood = star['blood_type'][0:2]bloods.append(blood)plt.subplot(1, 2, 2)
plt.scatter(bloods, heights, marker="v", color='red')
plt.axis()plt.title("身高-血型散点图")
plt.xlabel("血型")
# plt.ylabel("身高(cm)")
plt.show()

六、作业:选取三位选手,并为这三位选手分别选取三张照片,以九宫格的形式可视化出来。

  • 这里使用数组保存三个选手的姓名
  • 循环读取和输出3*3九宫格
### 此处为选手显示照片的代码
import matplotlib.pyplot as plt # plt 用于显示图片
import matplotlib.image as mpimg # mpimg 用于读取图片
import numpy as npname = ['黄圣依', '吴昕', '张雨绮']for j in range(3):for i in range(3):lena = mpimg.imread('work/pics/' + name[j] + '/' + str(i + 1) + '.jpg')  # 读取和代码处于同一目录下的 lena.png# 此时 lena 就已经是一个 np.array 了,可以对它进行任意处理lena.shape  # (512, 512, 3)plt.subplot(3, 3, j * 3 + i + 1)plt.imshow(lena)  # 显示图片plt.axis('off')  # 不显示坐标轴
plt.show()

总结

  1. 本次是第一次进行数据爬取,对代码的细节还不熟悉,只能“依葫芦画瓢”,对代码部分逻辑问题进行修正。
  2. 可视化数据分析还不够到位,还需继续学习数据分析方法和可视化方法。

百度AI深度学习课程 作业1--爬取《乘风破浪的姐姐》所有选手信息相关推荐

  1. 百度AI深度学习课程——《乘风破浪的姐姐》数据爬取

    <乘风破浪的姐姐>数据爬取 最近在学习百度AI深度学习课程,课程有一节讲解的是爬取<乘风破浪的姐姐>选手信息,以及选手百度百科中的图集图片.课程链接如下:https://ais ...

  2. 吴恩达deeplearning.ai深度学习课程空白作业

      吴恩达deeplearning.ai深度学习课程的空白作业,包括深度学习微专业五门课程的全部空白编程作业,经多方整理而来.网上找来的作业好多都是已经被别人写过的,不便于自己练习,而且很多都缺失各种 ...

  3. deeplearing.ai 深度学习课程笔记

    deeplearing.ai 深度学习课程笔记 一.神经网络与机器学习 直观理解神经网络.随着神经网络层的加深,所提取的特征(函数)不断组合,最终得到更宏观.更复杂的所需要的特征.简单的例子比如房屋价 ...

  4. Deeplearning.ai深度学习课程笔记-在线版

    注意:请点击阅读原文 课程概述 课程视频离线版本可以到github:https://github.com/fengdu78/deeplearning_ai_books 查找下载. 课程地址:https ...

  5. 第4篇 Fast AI深度学习课程——深度学习在回归预测、NLP等领域的应用

    前面几节叙述了卷积神经网络在图像分类中的应用,本节将描述深度学习网络在诸如回归预测.自然语言处理等领域的应用.主要内容如下: Drop Out策略,以及Fast.AI附加层架构分析. 结构化时间序列的 ...

  6. python爬取千图网图片并保存_Python数据分析与挖掘实战-课程作业5爬取千图网某个频道的高清图片...

    作业要求:爬取千图网(http://www.58pic.com)某个频道的高清图片 作业难点:正确找到图片链接并用正则表达式写出 代码如下: """ Created on ...

  7. python爬取乘风破浪的姐姐弹幕--芒果TV爬虫

    不知道大家有木有收看兴风作浪 乘风破浪的姐姐们吖?你最喜欢哪个姐姐呢?看看哪个姐姐最受弹幕欢迎吧 今天(昨天),先把芒果TV的<乘风破浪的姐姐>弹幕爬下来再说 from bs4 impor ...

  8. AI Studio 学习 Go 豆瓣电影爬取

    分析 1.首先获得每个主页面的内容 豆瓣电影 Top 250 URL:https://movie.douban.com/top250 第一页URL:https://movie.douban.com/t ...

  9. github标星8331+:吴恩达深度学习课程资源(完整笔记、中英文字幕视频、python作业,提供百度云镜像!)...

    吴恩达老师的深度学习课程(deeplearning.ai),可以说是深度学习入门的最热门课程,我和志愿者编写了这门课的笔记,并在github开源,star数达到8331+,曾经有相关报道文章.为解决g ...

最新文章

  1. 集合打印出来的信息不是输入的信息
  2. iOS UI 18 数据库
  3. 混合云下割裂的Web安全管理挑战如何破?
  4. 1273 - Unknown collation: 'utf8mb4_0900_ai_ci'
  5. python字符串转浮点数_python – 无法将字符串列表转换为浮点数
  6. BZOJ2795/2890/3647 [Poi2012]A Horrible Poem 【字符串hash】
  7. 计算机组成原理学习-哈工大《计算机组成原理》第四章-上篇
  8. 关于音频采样率,音频帧率,每次采集多少字节的理解
  9. 颜色空间(RGB、YUV、YIQ、CMY)
  10. 软件需求分析学习日记(一)需求工程概述
  11. 冰羚-IceOryx FAQ翻译
  12. Python调用cmd
  13. svn造成桌面图标显示问号的处理办法
  14. 手机屏幕显示正常但是触摸有一部分出问题,是内屏坏了吗?保修期内手机该不该走官方售后?
  15. JWS 批注参考WebService注解
  16. 如何把原型保存为图片?
  17. 蜗牛星际风扇噪音的简单解决方案
  18. csdn的markdown编辑器如何保持图片原始大小?
  19. 筛选英语高于计算机成,计算机应用基础--excel操作题2
  20. Zookeeper 面试题及答案

热门文章

  1. DO447使用过滤器和插件转换器--实现高级循环
  2. 网站服务器p2p更新需要多久,《彩虹六号》更新计划 将升级服务器并移除P2P功能...
  3. Javascript 核心方法加密,JS方法完美在线加密工具介绍及演示
  4. k8s容器驱逐之ephemeral-storage
  5. 良好棉花是如何认证的?标准内容是什么?
  6. JAVA for循环执行顺序
  7. 微信小程序登录授权流程
  8. 【算法设计与分析】算法的时间复杂度(介绍O渐近上界,Ω渐近下界,θ准确的界)
  9. 高通平台稳定性分析-CFI failure
  10. 如何使用纯CSS实现固定宽高比div?