Python爬虫爬取北京空气质量数据并分析

发布时间 2023-06-11 01:46:38作者: 罗宾aa

一.选题背景

空气质量(Air quality)是依据空气中污染物浓度的高低来判断的,其好坏反映了空气污染程度。空气污染是一个复杂的现象,在特定时间和地点空气污染物浓度受到许多因素影响。空气质量不达标的危害有很多,例如1、危害人体:当大气中污染物的浓度很高时,会造成人体急性污染中毒,或使病状恶化,甚至在几天内夺去几千人的生命。2、对植物的危害:当污染物浓度很高时,会对植物产生急性危害,使植物叶表面产生伤斑,导致枝叶枯萎脱落;3、影响气候:空气污染会减少阳光到达地面的太阳辐射量,增加大气降水量,同时也会增加下酸雨的机率,而酸雨能使大片森林和农作物毁坏,能使纸品、纺织品、皮革制品等腐蚀破碎,能使金属的防锈涂料变质而降低保护作用,还会腐蚀污染建筑物。

二.大数据分析设计方案

从网址中爬取完数据后,在python环境中导入pandas、plotly等库进行数据整理,经过数据清洗,检查数据等,然后进行可视化处理,找到空气质量的关系完成数据分析。

数据来源:'http://tianqihoubao.com/aqi/beijing-{year}0{month}.html'

思路:对数据集进行分析,进行数据清洗,根据所需内容对数据进行可视化最后得到图像并分析结果。

 

三.大数据分析步骤

爬取网站生成csv文件的过程。

import csv
import random
import time
import pandas as pd
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False


class Spider(object):
    def __init__(self):
        pass

    def get_data_and_save(self):
        with open('data.csv', 'w', encoding='utf-8', newline='') as f:
            csv_writer = csv.writer(f)
            csv_writer.writerow(['日期', '质量等级', 'AQI指数', '当天AQI排名', 'PM2.5', 'PM10', 'So2', 'No2', 'Co', 'O3'])
            years = [2020, 2021, 2022]
            #2020年到2022年
            months = range(1, 13)
            #1月到12月
            for year in years:
                for month in months:
                    if month < 10:
                        url = f'http://tianqihoubao.com/aqi/beijing-{year}0{month}.html'
                    else:
                        url = f'http://tianqihoubao.com/aqi/beijing-{year}{month}.html'
                    res = requests.get(url).text
                    soup = BeautifulSoup(res, 'html.parser')
                    for attr in soup.find_all('tr')[1:]:
                        one_day_data = list()
                        for index in range(0, 10):
                            one_day_data.append(attr.find_all('td')[index].get_text().strip())
                        csv_writer.writerow(one_day_data)
                    time.sleep(2 + random.random())
                    print(year, month)

    def drawing(self):
        csv_df = pd.read_csv('data.csv', encoding='GBK')
        csv_df['日期'] = pd.to_datetime(csv_df['日期'])
        csv_df.index = csv_df['日期']
        del csv_df['日期']

        str_data = '2020-01-01'
        end_data = '2020-01-31'
        new_split_df = csv_df[str_data:end_data]
        values_count = new_split_df['质量等级'].value_counts().items()
        total = new_split_df['质量等级'].value_counts().tolist()
        label = new_split_df['质量等级'].value_counts().index
        explode = [0.01 for i in range(len(total))]
        fig, axes = plt.subplots(3, 1, figsize=(10, 8))
       


if __name__ == '__main__':
    spider = Spider()
    # 获取数据,保存数据
    spider.get_data_and_save()
    # 画分析图
    spider.drawing()

数据清洗

 ①导入相应模块以及数据集

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
df

  

 

 ②处理缺失值

发现无缺失值

 

重复值处理

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
#重复值处理
df=df.drop_duplicates()
df

  

 ④清除空值

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
#清除空值
datas = df.dropna()
display(datas)

 

⑤查看是有有true

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
df.isna().any()
#s是否有true值

 

 数据分析与数据可视化:

字典统计法:

# Author:xueling
# 先打开一篇我们要统计的文章,并读取内容
f = open(r'data.csv', 'r', encoding='utf-8')
article = f.read()
# 建立一个空字典来存储统计结果
d = {}
# 遍历整篇文章
for i in article:
    d[i] = d.get(i,0) + 1  # 字频统计
    # 在此基础上我们还可以做一个排序:
    ls = sorted(list(d.items()), key= lambda x:x[1], reverse=True)
print(d)
f.close()

 

 哈希表统计法

# Author:xueling
# 在colletions 导入哈希表的包
from collections import defaultdict
# 打开一个要统计的文件
f = open(r'data.csv', 'r', encoding='utf-8')
article = f.read()
# d是通过defaultdict生成的一个哈希表,其中value我们给int型的数据类型,来记录字符数
d = defaultdict(int)
# article里每一个字我们把它当做哈希表里的key,每有一个字就给value + 1,value默认值就是0
for key in article:
    d[key] += 1
print(d)

 

 数据分类

 

绘制AQI与PM2.5的关系散点图

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
#绘制 aqi 和 pm2.5 的关系散点图
# 设置图像尺寸
plt.figure(figsize=(15, 10))
# 绘制散点图,横坐标为aqi数据的第二列,纵坐标为aqi数据的第四列
plt.scatter(df[df.columns[1]], df[df.columns[3]])
# 设置横轴标签为'AQI',字体大小为20
plt.xlabel('空气等级', fontsize=20)
# 设置纵轴标签为'PM2.5',字体大小为20
plt.ylabel('AQI', fontsize=20)
# 设置图像标题为'AQI和PM2.5的关系散点图',字体大小为25
plt.title('空气质量等级分类散点图', fontsize=25)
# 显示图像
plt.show()

 

 

 

绘制空气等级质量的单变量分布图

import pandas as pd
import numpy as np
import seaborn as sns
import seaborn as sn
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
# 绘制空气质量等级单变量分布图
# 绘制以第三列为 x 轴,数据来源为 aqi 的计数图
sn.countplot(x=df.columns[2], data=df)
# 设置标题为“空气质量等级单变量分布图”
plt.title("空气质量等级单变量分布图")
# 设置 x 轴标签为“质量等级”
plt.xlabel("质量等级")
# 设置 y 轴标签为“aqi”
plt.ylabel("aqi")
# 显示图像
plt.show()

 

 

 可知,AQI指数越高,空气质量越差。

制作2020-2022年空气质量饼图

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt

# 读文件,去无用字段
bj_date = pd.read_csv('data.csv')
# print(bj_date.head(30))
# 数据清洗
#bj_date.drop(bj_date[np.isnan(bj_date['PM_US Post'])].index, inplace=True)


# 空气质量定级
def get_level(AQI指数):
    if AQI指数 < 35:
        return ''
    elif AQI指数 < 75:
        return ''
    elif AQI指数 < 150:
        return '轻度污染'
    elif AQI指数 < 250:
        return '中度污染'
    elif AQI指数 >= 250:
        return '高度污染'


# 给原始数据添加新列表level
bj_date.loc[:, 'level'] = bj_date['AQI指数'].apply(get_level)
print(bj_date)
# 统计各种空气质量的比列
bj_level=bj_date.groupby(['level']).size() / len(bj_date)
print(bj_level)
#画图
matplotlib.rcParams['font.sans-serif'] = 'SimHei'
l=['中度污染','','','轻度污染','高度污染']
plt.pie(bj_level,labels=l,autopct='%.2f%%')
plt.title('北京空气质量指数')
plt.show()

 

 这三年中,优良空气占比高。

 绘制PM2.5与AQI的线性回归图

import pandas as pd
import numpy as np
import seaborn as sns
import seaborn as sn
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
# 绘制PM2.5与AQI的线性回归拟合图
# 调用seaborn库的regplot函数,将PM2.5含量(ppm)作为x轴,AQI作为y轴,数据源为aqi
sn.regplot(x='PM2.5',  y='AQI指数',  data=df)
# 设定图表标题为  'PM2.5与AQI的线性回归拟合图'
plt.title('PM2.5与AQI的线性回归拟合图')
# 设定图表x轴标签为'PM2.5含量(ppm)'
plt.xlabel('PM2.5含量(ppm)')
# 设定图表y轴标签为'AQI'
plt.ylabel('AQI')
# 显示图表
plt.show()

 可以看出,AQI排放量与PM2.5成正比,AQI排放越高PM2.5指数越大,空气越差。

绘制各污染物之间的特征相关性热力分布图

import pandas as pd
import numpy as np
import seaborn as sns
import seaborn as sn
import matplotlib.pyplot as plt
df=pd.read_csv('data.csv')
# 绘制特征相关性热力图
# 设置画布大小
plt.figure(figsize=(17, 14))
# 计算相关系数并赋值给变量 corr
corr = df[['AQI指数', 'PM2.5', 'PM10', 'So2', 'Co', 'No2', 'O3']].corr()
# 以热图的形式展示相关性,并用蓝红色调表示,同时在每个方格中显示数值,并设置线宽为1
sn.heatmap(corr, cmap='RdBu_r', annot=True, linewidths=1)
# 设置热图的标题,并设置字体大小为25
plt.title("各污染物之间的特征相关性热力分布图", fontsize=25)
# 设置x轴标签字体大小为15
plt.xticks(fontsize=15)
# 设置y轴标签字体大小为15
plt.yticks(fontsize=15)
# 展示画布
plt.show()

 

 

绘制每日So2与AQI排放量的条形图

# 打开清洗后的数据文件'data.csv'
import pandas as pd
df_new = pd.read_csv('data.csv')
df_new
import matplotlib.pyplot as plt   #导入matplotlib库中的pyplot模块,pyplot是用于创建图表的主要函数
df_new['当天AQI排名'].value_counts().nlargest(10).plot.bar(figsize=(14,6),fontsize= 13)
plt.title('柱形图',fontsize= 20)
plt.xlabel('AQI',fontsize= 16)
plt.xticks(rotation=0)   #设置X轴刻度标签的旋转角度。xticks是指X轴上的刻度,rotation参数指定刻度标签的旋转度数,0表示不旋转。若刻度标签内容过长,旋转角度可以调整为其他角度,以便更好地展示文本。
plt.ylabel('So2',fontsize= 16)
plt.legend()   #显示标签
plt.rcParams['font.sans-serif'] = ['SimHei']  #设置显示中文字符的字体
plt.grid()   #显示网格线
plt.show()   #s显示图形,

 

 So2排放量越高,AQI指数越大。

总代码:

  1 import csv
  2 import random
  3 import time
  4 import pandas as pd
  5 import requests
  6 from bs4 import BeautifulSoup
  7 import matplotlib.pyplot as plt
  8 import numpy as np
  9 import seaborn as sns
 10 import jieba
11 #导入对应包 12 plt.rcParams["font.sans-serif"] = ["SimHei"] 13 plt.rcParams["axes.unicode_minus"] = False 14 15 16 class Spider(object): 17 def __init__(self): 18 pass 19 20 def get_data_and_save(self): 21 with open('data.csv', 'w', encoding='utf-8', newline='') as f: 22 csv_writer = csv.writer(f) 23 csv_writer.writerow(['日期', '质量等级', 'AQI指数', '当天AQI排名', 'PM2.5', 'PM10', 'So2', 'No2', 'Co', 'O3']) 24 years = [2020, 2021, 2022] 25 #2020年到2022年 26 months = range(1, 13) 27 #1月到12月 28 for year in years: 29 for month in months: 30 if month < 10: 31 url = f'http://tianqihoubao.com/aqi/beijing-{year}0{month}.html' 32 else: 33 url = f'http://tianqihoubao.com/aqi/beijing-{year}{month}.html' 34 res = requests.get(url).text 35 soup = BeautifulSoup(res, 'html.parser') 36 for attr in soup.find_all('tr')[1:]: 37 one_day_data = list() 38 for index in range(0, 10): 39 one_day_data.append(attr.find_all('td')[index].get_text().strip()) 40 csv_writer.writerow(one_day_data) 41 time.sleep(2 + random.random()) 42 print(year, month) 43 44 def drawing(self): 45 csv_df = pd.read_csv('data.csv', encoding='GBK') 46 csv_df['日期'] = pd.to_datetime(csv_df['日期']) 47 csv_df.index = csv_df['日期'] 48 del csv_df['日期'] 49 50 str_data = '2020-01-01' 51 end_data = '2020-01-31' 52 new_split_df = csv_df[str_data:end_data] 53 values_count = new_split_df['质量等级'].value_counts().items() 54 total = new_split_df['质量等级'].value_counts().tolist() 55 label = new_split_df['质量等级'].value_counts().index 56 explode = [0.01 for i in range(len(total))] 57 fig, axes = plt.subplots(3, 1, figsize=(10, 8)) 58 59 60 61 if __name__ == '__main__': 62 spider = Spider() 63 # 获取数据,保存数据 64 spider.get_data_and_save() 65 # 画分析图 66 spider.drawing() 67 df=pd.read_csv('data.csv') 68 df 69 #导出CSV 70 71 #处理缺失值 72 df.isnull().sum() 73 74 df=pd.read_csv('data.csv') 75 #重复值处理 76 df=df.drop_duplicates() 77 df 78 79 import matplotlib.pyplot as plt 80 df=pd.read_csv('data.csv') 81 df.isna().any() 82 #判断是否有TRUE 83 84 import matplotlib.pyplot as plt 85 df=pd.read_csv('data.csv') 86 #清除空值 87 datas = df.dropna() 88 display(datas) 89 90 df=pd.read_csv('data.csv') 91 #绘制 aqi 和 pm2.5 的关系散点图 92 # 设置图像尺寸 93 plt.figure(figsize=(15, 10)) 94 # 绘制散点图,横坐标为aqi数据的第二列,纵坐标为aqi数据的第四列 95 plt.scatter(df[df.columns[1]], df[df.columns[3]]) 96 # 设置横轴标签为'AQI',字体大小为20 97 plt.xlabel('空气等级', fontsize=20) 98 # 设置纵轴标签为'PM2.5',字体大小为20 99 plt.ylabel('AQI', fontsize=20) 100 # 设置图像标题为'AQI和PM2.5的关系散点图',字体大小为25 101 plt.title('空气质量等级分类散点图', fontsize=25) 102 # 显示图像 103 plt.show() 104 105 df=pd.read_csv('data.csv') 106 # 绘制空气质量等级单变量分布图 107 # 绘制以第三列为 x 轴,数据来源为 aqi 的计数图 108 sn.countplot(x=df.columns[2], data=df) 109 # 设置标题为“空气质量等级单变量分布图” 110 plt.title("空气质量等级单变量分布图") 111 # 设置 x 轴标签为“质量等级” 112 plt.xlabel("质量等级") 113 # 设置 y 轴标签为“aqi” 114 plt.ylabel("aqi") 115 # 显示图像 116 plt.show() 117 118 df=pd.read_csv('data.csv') 119 # 绘制PM2.5与AQI的线性回归拟合图 120 # 调用seaborn库的regplot函数,将PM2.5含量(ppm)作为x轴,AQI作为y轴,数据源为aqi 121 sn.regplot(x='PM2.5', y='AQI指数', data=df) 122 # 设定图表标题为 'PM2.5与AQI的线性回归拟合图' 123 plt.title('PM2.5与AQI的线性回归拟合图') 124 # 设定图表x轴标签为'PM2.5含量(ppm)' 125 plt.xlabel('PM2.5含量(ppm)') 126 # 设定图表y轴标签为'AQI' 127 plt.ylabel('AQI') 128 # 显示图表 129 plt.show() 130 131 df=pd.read_csv('data.csv') 132 # 绘制特征相关性热力图 133 # 设置画布大小 134 plt.figure(figsize=(17, 14)) 135 # 计算相关系数并赋值给变量 corr 136 corr = df[['AQI指数', 'PM2.5', 'PM10', 'So2', 'Co', 'No2', 'O3']].corr() 137 # 以热图的形式展示相关性,并用蓝红色调表示,同时在每个方格中显示数值,并设置线宽为1 138 sn.heatmap(corr, cmap='RdBu_r', annot=True, linewidths=1) 139 # 设置热图的标题,并设置字体大小为25 140 plt.title("各污染物之间的特征相关性热力分布图", fontsize=25) 141 # 设置x轴标签字体大小为15 142 plt.xticks(fontsize=15) 143 # 设置y轴标签字体大小为15 144 plt.yticks(fontsize=15) 145 # 展示画布 146 plt.show() 147 148 # Author:xueling 149 # 先打开一篇我们要统计的文章,并读取内容 150 f = open(r'data.csv', 'r', encoding='utf-8') 151 article = f.read() 152 # 建立一个空字典来存储统计结果 153 d = {} 154 # 遍历整篇文章 155 for i in article: 156 d[i] = d.get(i,0) + 1 157 # 字频统计 158 # 在此基础上我们还可以做一个排序: 159 ls = sorted(list(d.items()), key= lambda x:x[1], reverse=True) 160 print(d) 161 f.close() 162 #字典统计方法 163 # Author:xueling 164 # 在colletions 导入哈希表的包 165 from collections import defaultdict 166 # 打开一个要统计的文件 167 f = open(r'data.csv', 'r', encoding='utf-8') 168 article = f.read() 169 # d是通过defaultdict生成的一个哈希表,其中value我们给int型的数据类型,来记录字符数 170 d = defaultdict(int) 171 # article里每一个字我们把它当做哈希表里的key,每有一个字就给value + 1,value默认值就是0 172 for key in article: 173 d[key] += 1 174 print(d) 175 #哈希表统计方法 176 177 # 读文件,去无用字段 178 bj_date = pd.read_csv('data.csv') 179 # print(bj_date.head(30)) 180 # 数据清洗 181 #bj_date.drop(bj_date[np.isnan(bj_date['PM_US Post'])].index, inplace=True) 182 183 184 # 空气质量定级 185 def get_level(AQI指数): 186 if AQI指数 < 35: 187 return '' 188 elif AQI指数 < 75: 189 return '' 190 elif AQI指数 < 150: 191 return '轻度污染' 192 elif AQI指数 < 250: 193 return '中度污染' 194 elif AQI指数 >= 250: 195 return '高度污染' 196 197 198 # 给原始数据添加新列表level 199 bj_date.loc[:, 'level'] = bj_date['AQI指数'].apply(get_level) 200 print(bj_date) 201 # 统计各种空气质量的比列 202 bj_level=bj_date.groupby(['level']).size() / len(bj_date) 203 print(bj_level) 204 #画图 205 matplotlib.rcParams['font.sans-serif'] = 'SimHei' 206 l=['中度污染','','','轻度污染','高度污染'] 207 plt.pie(bj_level,labels=l,autopct='%.2f%%') 208 plt.title('北京空气质量指数') 209 plt.show() 210 211 # 打开清洗后的数据文件'data.csv' 212 import pandas as pd 213 df_new = pd.read_csv('data.csv') 214 df_new 215 import matplotlib.pyplot as plt 216 #导入matplotlib库中的pyplot模块,pyplot是用于创建图表的主要函数 217 df_new['当天AQI排名'].value_counts().nlargest(10).plot.bar(figsize=(14,6),fontsize= 13) 218 plt.title('柱形图',fontsize= 20) 219 plt.xlabel('AQI',fontsize= 16) 220 plt.xticks(rotation=0) 221 #设置X轴刻度标签的旋转角度。xticks是指X轴上的刻度,rotation参数指定刻度标签的旋转度数,0表示不旋转。若刻度标签内容过长,旋转角度可以调整为其他角度,以便更好地展示文本。 222 plt.ylabel('So2',fontsize= 16) 223 plt.legend() 224 #显示标签 225 plt.rcParams['font.sans-serif'] = ['SimHei'] 226 #设置显示中文字符的字体 227 plt.grid() 228 #显示网格线 229 plt.show() 230 #s显示图形,

总结:

1.pm2.5,pm10,so2,no2,co,o3等有毒气体对AQI指数的影响,有毒气体排放越大,AQI指数越大,AQI指数越大,空气质量越差。

2.我们应爱护环境,减少有毒气体的排放,坚持绿色发展。

改进的建议包括:

增加更多的数据源,以获得更全面和准确的数据,可以提却更多的字段信息,从不同角度去分析“空气污染程度”的普及程度。

进一步优化爬虫程序的效率和稳定性。

进一步深入数据分析和建模,例如使用机器学习算法进行情感分析或预测模型的构建。

增加更多的数据可视化方法和图表类型,以更好地展示数据和结论。

要对所获取的文本进行更加精确的分词以及进行聚类,使所得到的分词更具有主题性。

通过不断改进和完善,可以使网络爬虫程序更具实用性和可靠性,并为空气污染相关的数据分析提供更有价值的见解。