Python爬虫实战:5分钟高效抓取政府公开数据指南
政府网站作为权威数据来源,蕴藏着大量有价值的公开信息。对于数据分析师、市场研究人员或政策观察者来说,能够快速获取这些结构化数据至关重要。本文将手把手教你用Python构建一个高效、合规的政府数据抓取工具,整个过程仅需5分钟即可完成核心功能搭建。
1. 准备工作与环境配置
在开始编写爬虫之前,我们需要确保开发环境准备就绪。推荐使用Python 3.8及以上版本,这是目前大多数爬虫库支持最稳定的版本。
首先安装必要的依赖库:
pip install requests beautifulsoup4 pandas这三个库构成了我们爬虫的基础工具链:
requests:用于发送HTTP请求beautifulsoup4:解析HTML文档pandas:数据清洗和存储
提示:建议在虚拟环境中安装这些依赖,避免污染全局Python环境。可以使用
python -m venv myenv创建虚拟环境。
政府网站通常采用以下几种数据提供方式:
- 静态HTML页面(传统方式)
- 动态加载的JSON接口(现代网站常用)
- 文件下载(如Excel、PDF等)
我们将重点针对第二种情况——通过API接口获取JSON数据,这是目前最高效的获取方式。
2. 分析目标网站结构
以某地方政府采购网为例,我们需要获取其招标公告数据。打开浏览器开发者工具(Chrome中按F12),切换到Network选项卡,然后刷新页面。
观察网络请求,特别关注XHR类型的请求,这些通常是数据接口。找到类似/api/announcement/list这样的端点,这就是我们的目标接口。
关键参数通常包括:
pageSize:每页数据量pageNum:当前页码categoryId:分类ID_t:时间戳(防缓存)
通过多次请求观察,我们可以确定哪些参数是必需的,哪些是可选的。例如:
| 参数名 | 是否必需 | 说明 |
|---|---|---|
| pageSize | 是 | 每页返回记录数 |
| pageNum | 是 | 当前页码 |
| _t | 是 | 13位时间戳 |
| keyword | 否 | 搜索关键词 |
3. 构建请求头与参数
政府网站通常对爬虫较为友好,但仍需模拟浏览器行为以避免被拒绝服务。以下是一个典型的请求头配置:
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://www.example.gov.cn/', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }对于POST请求,我们需要构造表单数据。观察接口请求,参数通常以form-data形式发送:
import time params = { 'pageSize': 10, 'pageNum': 1, '_t': int(time.time() * 1000) # 生成13位时间戳 }4. 发送请求与处理响应
使用requests库发送POST请求:
import requests url = 'https://www.example.gov.cn/api/announcement/list' response = requests.post(url, headers=headers, data=params) if response.status_code == 200: data = response.json() print(f"成功获取{len(data['list'])}条数据") else: print(f"请求失败,状态码:{response.status_code}")处理返回的JSON数据时,建议进行以下检查:
- 检查
response.status_code确保请求成功 - 检查返回数据是否包含预期的字段
- 处理可能的分页逻辑
5. 数据存储与后续处理
获取到数据后,我们可以选择多种存储方式。对于结构化数据,Pandas提供了便捷的处理方法:
import pandas as pd # 假设data['list']是我们获取的数据列表 df = pd.DataFrame(data['list']) # 保存为CSV文件 df.to_csv('government_data.csv', index=False, encoding='utf_8_sig') # 保存为Excel文件 df.to_excel('government_data.xlsx', index=False)对于更复杂的场景,可以考虑:
- 存储到数据库(如MySQL、MongoDB)
- 定期增量更新
- 添加数据清洗和转换逻辑
6. 实战技巧与注意事项
在实际操作中,有几个关键点需要注意:
请求频率控制:
- 添加适当的延迟(如
time.sleep(1)) - 避免短时间内发送大量请求
- 添加适当的延迟(如
错误处理:
- 网络异常捕获
- 数据格式验证
- 重试机制实现
from retrying import retry @retry(stop_max_attempt_number=3, wait_fixed=2000) def safe_request(url, headers, params): try: response = requests.post(url, headers=headers, data=params, timeout=10) return response.json() except Exception as e: print(f"请求异常:{str(e)}") raise数据更新策略:
- 记录最后更新时间
- 只获取新增或变更的数据
- 避免重复处理相同数据
合规性检查:
- 确认目标数据确实属于公开范围
- 遵守网站的robots.txt规定
- 不获取敏感或个人隐私信息
7. 完整代码示例
以下是一个完整的政府数据抓取示例,包含了上述所有关键要素:
import requests import time import pandas as pd from retrying import retry # 配置请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://www.example.gov.cn/', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } # 重试装饰器 @retry(stop_max_attempt_number=3, wait_fixed=2000) def fetch_data(page_num, page_size=10): url = 'https://www.example.gov.cn/api/announcement/list' params = { 'pageSize': page_size, 'pageNum': page_num, '_t': int(time.time() * 1000) } try: response = requests.post(url, headers=headers, data=params, timeout=10) response.raise_for_status() return response.json()['list'] except Exception as e: print(f"第{page_num}页获取失败: {str(e)}") return [] # 主程序 def main(): all_data = [] for page in range(1, 6): # 获取前5页数据 print(f"正在获取第{page}页数据...") page_data = fetch_data(page) all_data.extend(page_data) time.sleep(1) # 礼貌性延迟 if all_data: df = pd.DataFrame(all_data) df.to_csv('government_procurement.csv', index=False, encoding='utf_8_sig') print(f"成功保存{len(df)}条数据到CSV文件") else: print("未获取到有效数据") if __name__ == '__main__': main()这个脚本实现了:
- 分页数据获取
- 请求重试机制
- 错误处理
- 数据存储
- 请求频率控制
在实际项目中,根据具体需求可能需要调整参数或添加更多功能,但这个框架已经涵盖了政府数据抓取的核心流程。