查看全课大纲(第 26 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

实战:获取国内城市空气质量指数数据

约 15 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

小象实战讲义 · Python数据分析实战

本节我们将通过一个实战项目来巩固第三课《网络数据的获取与表示》的学习。该项目旨在获取国内城市空气质量指数(AQI)数据,这类数据通常实时或每日更新,通过编写自动化代码定期运行,就能持续获取最新数据,为后续的分析处理提供便利。本节将重点讲解如何设计爬虫流程来获取这类结构化数据。

💡 核心导读

  • 项目目标:爬取国内所有城市的AQI及相关污染物浓度数据,并保存为本地CSV文件
  • 网站结构分析:识别一级页面(城市列表页)与二级页面(城市详情页)的层级关系
  • 数据传递机制:学习如何在Scrapy框架中使用meta参数在不同解析函数间传递数据
  • 编码处理:了解CSV文件在不同工具(如Excel)中打开时的编码问题及解决方案

网站结构与爬取思路

目标网站为PM2.5监测平台(http://www.pm25.in/),其结构清晰:

  • 一级页面:首页列出所有城市的名称和链接(相对路径)
  • 二级页面:每个城市的详情页,包含AQI、PM2.5、PM10、一氧化碳、二氧化氮等具体指标

爬取流程分为两步:

  1. 解析一级页面,获取所有城市的名称和详情页链接(需拼接为完整URL)
  2. 对每个城市详情页发起请求,解析其中的各项空气质量指标数据

这种“列表页→详情页”的爬取模式在实际项目中非常常见,核心挑战在于如何在一级页面解析和二级页面解析之间传递必要的信息(如城市名称)。

Scrapy项目结构回顾

虽然本课环境限制无法实际运行Scrapy代码,但理解其项目结构对掌握爬虫工程化思维至关重要。一个典型的Scrapy项目包含以下核心组件:

# 伪代码:items.py 中的 CityAqiItem 类定义
# 注:Scrapy框架不在本课白名单内,此处仅作概念演示
# 实际环境中需安装scrapy并创建项目

# 定义数据容器(Item),明确要爬取的字段
class CityAqiItem:
    def __init__(self):
        self.city_name = None   # 城市名称,从一级页面获取
        self.city_link = None   # 城市详情页链接(完整URL)
        self.aqi = None         # 空气质量指数,从二级页面获取
        self.pm2_5 = None       # PM2.5浓度
        self.pm10 = None        # PM10浓度
        self.co = None          # 一氧化碳
        self.no2 = None         # 二氧化氮
        # 其他污染物字段...
# 伪代码:pipelines.py 中的数据保存逻辑
# 演示如何将爬取到的数据保存为CSV文件

import csv

class CsvPipeline:
    def open_spider(self, spider):
        """爬虫启动时打开CSV文件并写入表头"""
        self.file = open('cities_aqi.csv', 'w', newline='', encoding='utf-8')
        self.writer = csv.writer(self.file)
        # 写入列名
        self.writer.writerow(['city_name', 'city_link', 'aqi', 'pm2_5', 'pm10', 'co', 'no2'])
    
    def process_item(self, item, spider):
        """处理每个爬取到的Item,写入CSV行"""
        row = [
            item.get('city_name', ''),
            item.get('city_link', ''),
            item.get('aqi', ''),
            item.get('pm2_5', ''),
            item.get('pm10', ''),
            item.get('co', ''),
            item.get('no2', '')
        ]
        self.writer.writerow(row)
        return item
    
    def close_spider(self, spider):
        """爬虫关闭时关闭文件"""
        self.file.close()

核心爬虫逻辑解析

爬虫的核心在于Spider类的编写,它定义了如何发起请求、如何解析响应、如何在页面间跳转。以下是关键逻辑的伪代码说明:

# 伪代码:spiders/aqi_spider.py 中的核心解析逻辑
# 演示一级页面解析、二级页面请求、数据传递的完整流程

class AqiSpider:
    name = "aqi_spider"
    start_urls = ["http://www.pm25.in/"]
    
    def parse(self, response):
        """解析一级页面(城市列表页)"""
        # 1. 使用BeautifulSoup或Scrapy Selector解析HTML
        # 2. 定位包含城市列表的容器(如特定的div或ul)
        # 3. 遍历每个城市条目,提取:
        #    - city_name: 城市名称(从<a>标签的text获取)
        #    - city_link: 详情页链接(将相对路径与基准URL拼接)
        
        # 4. 对于每个城市,创建CityAqiItem并填充city_name和city_link
        # 5. 发起对二级页面的请求,关键步骤:
        #    yield scrapy.Request(
        #        url=city_link,  # 二级页面URL
        #        callback=self.parse_city_detail,  # 二级页面解析函数
        #        meta={'item': item},  # 通过meta传递已部分填充的item
        #        dont_filter=True  # 不过滤重复请求
        #    )
    
    def parse_city_detail(self, response):
        """解析二级页面(城市详情页)"""
        # 1. 从response.meta中取出之前传递的item
        #    item = response.meta['item']
        
        # 2. 解析详情页中的空气质量数据
        #    定位数据容器:通常有特定class的div(如"span12 data")
        #    在容器内查找所有数值元素(如class="value"的div)
        
        # 3. 按顺序提取数值并填充到item中:
        #    item['aqi'] = values[0].text  # 第一个value是AQI
        #    item['pm2_5'] = values[1].text  # 第二个是PM2.5
        #    item['pm10'] = values[2].text  # 第三个是PM10
        #    ...依此类推
        
        # 4. 将完整item返回给引擎,由Pipeline处理
        #    yield item

关键机制说明:

  • meta参数:这是Scrapy中在不同请求/响应间传递数据的标准方式。在一级页面解析时,我们将部分填充的item放入meta,在二级页面解析时再从response.meta中取出,继续填充剩余字段。
  • 回调函数链:parse → Request → parse_city_detail 形成了一个完整的处理链,实现了页面跳转和数据累积。
  • URL拼接:一级页面中的链接通常是相对路径(如/beijing),需要与基准URL(http://www.pm25.in)拼接成完整URL。

编码问题与数据查看

爬取完成并保存为CSV文件后,可能会遇到编码问题。特别是用Excel直接打开UTF-8编码的CSV时,中文字符可能显示为乱码。这是因为Excel默认使用系统本地编码(如GBK)打开CSV文件。

正确在Excel中打开UTF-8编码CSV的方法:

  1. 打开Excel,选择“数据”选项卡
  2. 点击“从文本/CSV”
  3. 选择爬取得到的CSV文件
  4. 在导入向导中,将“文件原始格式”选择为“UTF-8”
  5. 确认分隔符为逗号,然后点击“加载”

这样就能正确显示包含中文城市名称的数据了。数据加载后,你可以利用Excel的排序、筛选功能,或使用Pandas进行更深入的分析,比如:

  • 按AQI值对城市进行排序,找出空气质量最好/最差的城市
  • 分析不同污染物之间的相关性
  • 将数据与地理信息结合,制作空气质量地图

📝 动手练一练

  1. 概念辨析:在Scrapy框架中,meta参数的主要作用是什么?为什么在爬取“列表页→详情页”这类网站时需要使用它?
👉 点击查看参考答案

meta参数的主要作用是在Scrapy的不同请求(Request)和响应(Response)之间传递数据。它是一个字典,可以携带任意可序列化的数据。

在“列表页→详情页”的爬取场景中,我们需要使用meta的原因是:

  • 数据分步获取:城市名称和链接在一级页面获取,而详细的空气质量数据在二级页面获取
  • 保持数据关联:需要将一级页面获取的城市信息“携带”到二级页面的解析过程中,确保最终每条完整记录都能正确关联到对应的城市
  • 实现方式:在一级页面解析时创建部分填充的Item(包含city_name和city_link),将其放入Request的meta参数中;在二级页面解析时,从response.meta中取出这个Item,继续填充剩余的字段(aqi、pm2_5等),最后返回完整的Item。

如果不使用meta,就需要通过其他方式(如URL参数、数据库临时存储)来维护这种跨页面的数据关联,实现起来会更加复杂。

  1. 流程设计:如果目标网站改版,城市详情页的HTML结构发生变化,原来定位数据的CSS选择器div.span12.data div.value不再有效。你应该如何排查和解决这个问题?
👉 点击查看参考答案

解决这类问题的系统化步骤如下:

  1. 确认问题:首先在浏览器中手动访问几个城市的详情页,查看页面是否正常加载,数据是否仍然存在但HTML结构发生了变化。

  2. 分析新结构:使用浏览器的开发者工具(F12)检查元素:

    • 查看空气质量数据现在包含在哪个HTML元素中
    • 查看该元素的新class、id或其他属性
    • 注意数据排列顺序是否发生变化
  3. 更新选择器:根据新的HTML结构,更新解析代码中的CSS选择器或XPath表达式。例如:

    • 如果数据现在放在<div class="air-quality-data">中,则更新为div.air-quality-data div.value
    • 如果使用了不同的class名,如<span class="aqi-value">,则相应调整
  4. 测试验证:选择几个有代表性的城市页面进行测试,确保能正确解析出所有字段。

  5. 处理异常情况:考虑网站可能存在的其他变化:

    • 数据顺序是否改变(原来第一个是AQI,现在可能是PM2.5)
    • 是否有新增或删除的指标字段
    • 数值格式是否变化(如单位、小数位数)
  6. 代码健壮性改进:可以考虑增加错误处理逻辑,当解析失败时记录日志,而不是直接崩溃,便于后续排查。

在实际项目中,网站改版是常见情况,良好的日志记录和监控能帮助快速发现和解决这类问题。

本章小结

通过本实战项目,我们完整演练了使用Scrapy框架爬取结构化数据的全过程。这个项目虽然基于特定网站,但其中体现的爬虫设计模式具有普遍适用性:

  • 网站结构分析是爬虫开发的第一步,需要清晰理解页面层级和数据分布
  • 数据模型设计(Item定义)有助于明确爬取目标,使代码更清晰
  • 跨页面数据传递(使用meta)是处理多级页面的关键技术
  • 编码处理是数据持久化时不可忽视的细节,特别是涉及多语言内容时

📋 行动清单

  • 尝试分析一个你感兴趣的网站,画出它的页面层级结构图
  • 思考如果目标网站需要登录才能访问数据,爬虫设计需要做哪些调整
  • 了解反爬虫机制(如IP封锁、验证码)及常见的应对策略

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 本节课件:实战:获取国内城市空气质量指数数据
    PDF · 220KB
    下载
  • 本课实战代码:爬取城市空气质量指数(AQI)数据(ipynb)
    ZIP · 2.5KB
    下载
  • 全套课件打包(第1-5章)
    ZIP · 12.8MB
    下载
  • 全套课件打包(第6-8章)
    ZIP · 15MB
    下载
  • 实战数据集:AppleStore 应用商城分析
    ZIP · 329KB
    下载
  • 实战数据集:女性服装电商分析
    ZIP · 2.8MB
    下载
  • Python 数据分析环境搭建指南
    PDF · 2MB
    下载
  • Scrapy 安装教程
    PDF · 12.7MB
    下载
  • 附加实战项目:AppleStore 应用商城数据分析
    ZIP · 0.3MB · ipynb + CSV 数据
    下载
  • 附加实战项目:银行电话营销数据分析
    ZIP · 0.4MB · ipynb + CSV 数据
    下载
  • 附加实战项目:女性服装电商评论数据分析
    ZIP · 2.7MB · ipynb + CSV 数据
    下载
  • 附加实战项目:美国化学学会杂志数据分析
    ZIP · 34.2MB · ipynb + SQLite 数据库
    下载