当前位置:首页>python>Python爬取中国政府网政策:近十年农业政策一键落盘 Excel

Python爬取中国政府网政策:近十年农业政策一键落盘 Excel

  • 2026-10-11 05:34:29
Python爬取中国政府网政策:近十年农业政策一键落盘 Excel

Hi, 我是PaperBrew,目前专注于本硕博论文写作方法、文献阅读方法、学术规范科普\/:PaperBrew_Tang

研途千嶂,PaperBrew伴君求索

做涉农、乡村振兴或公共政策研究,最磨人的往往不是读文件,而是把中国政府网上的公文一条条找齐、对齐字段、落到可分析的表格里。

本文只做一件事:用 Python 调用中国政府网政策文件库的搜索接口,按关键词抓取近十年相关政策,补全详情与正文,导出一份结构化 Excel。示例主题是“农业 / 农村 / 乡村振兴 / 三农 / 粮食”,关键词换成你的题目即可复用。

目标站点:https://www.gov.cn/

搜索接口:https://sousuo.www.gov.cn/search-gov/data

一、先看清:这不是“扒整页 HTML”,而是调搜索接口

打开中国政府网政策检索,按 F12 → Network,输入关键词搜索,会看到请求打到:

https://sousuo.www.gov.cn/search-gov/data

返回的是 JSON,不是一整页排好版的列表。这意味着技术路线是:

  1. 带参数 GET 搜索接口,翻页拿标题、发文机关、发文字号、日期、链接;

  2. 用链接去重,再按时间窗过滤;

  3. 逐条打开详情页,解析元数据表与正文;

  4. 按时间线排序,写入 Excel。

比静态列表页多一步“读接口”,但字段更干净,也更适合正式研究样本框。

二、环境与参数:先把时间窗和关键词定死

import re  import time  from datetime import datetime  from pathlib import Path  import pandas as pd  import requests  from bs4 import BeautifulSoup  SEARCH_API = "https://sousuo.www.gov.cn/search-gov/data"KEYWORDS = ["农业", "农村", "乡村振兴", "三农", "粮食"]  

以写作当天为终点,往前十年(按需修改)

END_DATE = datetime(2026, 7, 29)  START_DATE = datetime(2016, 7, 29)  DELAY = 1.0 # 详情页间隔,降低对服务器压力  OUT_FILE = Path.home() / "Desktop" / "中国政府网_农业政策_近十年.xlsx"SESSION = requests.Session()  SESSION.headers.update(  {  "User-Agent": (  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/120.0.0.0 Safari/537.36"),  "Referer": "https://www.gov.cn/",  }  )

依赖安装:

pip install requests beautifulsoup4 pandas openpyxl

注意三点:带上合理的 User-Agent 与 Referer;详情请求之间留 DELAY;关键词列表按课题改,不要一次塞几十个无关词。

三、第一步:搜索接口翻页,拼出政策目录

核心参数含义可以这样理解:

参数
作用
t=zhengcelibrary
走政策库检索
q
关键词
mintime
 / maxtime
时间窗
p
 / n
页码与每页条数
type=gwyzcwjk
公文政策文件库
sort=pubtime
按发布时间排序
def search_page(keyword: str, page: int, page_size: int = 50) -> list[dict]:  params = {  "t": "zhengcelibrary",  "q": keyword,  "timetype": "5",  "mintime": START_DATE.strftime("%Y-%m-%d"),  "maxtime": END_DATE.strftime("%Y-%m-%d"),  "sort": "pubtime",  "sortType": "1",  "searchfield": "title",  "p": str(page),  "n": str(page_size),  "type": "gwyzcwjk",  }  data = SESSION.get(SEARCH_API, params=params, timeout=30).json()  items = (  data.get("searchVO", {})  .get("catMap", {})  .get("gongwen", {})  .get("listVO", [])  or []  )  rows = []  for it in items:  title = re.sub(r"<[^>]+>", "", it.get("title") or "").strip()  url = (it.get("url") or "").strip()  if not title or not url:  continuepub = (it.get("pubtimeStr") or "").replace(".", "-")  rows.append(  {  "政策名称": title,  "出文单位": (it.get("puborg") or "").strip(),  "发文字号": (it.get("pcode") or "").strip(),  "主题分类": (it.get("childtype") or "").strip(),  "索引号": (it.get("index") or "").strip(),  "发布日期": pub,  "链接": url,  }  )  return rows

多关键词检索后,同一公文常被不同词命中,必须用链接去重。接口一般按时间倒序;当本页最旧一条已经早于起始年,可以提前停翻,少打无效请求。

def collect() -> list[dict]:  """多关键词翻页 → 去重 → 十年窗口过滤 → 按时间线从早到晚。"""merged = {}  for kw in KEYWORDS:  print(f"搜索:{kw}")  for page in range(1, 20): # 每词最多翻 20 页,可按题调整  rows = search_page(kw, page)  if not rows:  breakfor row in rows:  merged[row["链接"]] = row  oldest = parse_date(rows[-1]["发布日期"])  if oldest and oldest < START_DATE:  breaktime.sleep(0.4)  rows = [row for row in merged.values() if in_range(row["发布日期"])]  rows.sort(key=lambda x: parse_date(x["发布日期"]) or datetime.min)  return rows

日期解析写成小函数即可:兼容 2020-01-01、2020.01.01、2020年1月1日 等常见写法,再判断是否落在 [START_DATE, END_DATE]。

四、第二步:进详情页,补元数据与正文

搜索结果里已有标题、链接、大致日期;正式分析还需要详情页里的索引号、发文机关、成文日期,以及正文全文。

详情页元数据多在表格单元格中,标签形如“索引号”“主题分类”“发文机关”“成文日期”“发文字号”“发布日期”。正文常见容器:

• #UCAP-CONTENT

• .pages_content

• .TRS_Editor

建议优先用 html.parser。部分页面用 lxml 解析时可能丢正文,这是实操里踩过的坑。

def parse_table(soup: BeautifulSoup) -> dict:  label_map = {  "索引号": "索引号",  "主题分类": "主题分类",  "发文机关": "出文单位",  "成文日期": "成文日期",  "标题": "政策名称",  "发文字号": "发文字号",  "发布日期": "发布日期",  }  out = {}  for td in soup.select("table td"):  b = td.find("b") or td.find("strong")  if not b:  continuelabel = re.sub(r"[su3000::]", "", b.get_text())  field = next((v for k, v in label_map.items() if label.startswith(k)), None)  nxt = td.find_next_sibling("td")  if field and nxt:  val = nxt.get_text(" ", strip=True)  if val:  out[field] = val  return out  def parse_body(soup: BeautifulSoup) -> str:  box = (  soup.find("div", id="UCAP-CONTENT")  or soup.select_one(".pages_content")  or soup.select_one(".TRS_Editor")  )  if not box:  return""for tag in box.select("script, style"):  tag.decompose()  return re.sub(r"n{3,}", "nn", box.get_text("n", strip=True)).strip()  def fetch_detail(url: str) -> dict:  r = SESSION.get(url, timeout=40)  r.raise_for_status()  r.encoding = "utf-8"soup = BeautifulSoup(r.text, "html.parser")  info = parse_table(soup)  info["正文内容"] = parse_body(soup)  if not info.get("政策名称"):  h1 = soup.select_one("h1#ti, h1")  if h1:  info["政策名称"] = h1.get_text(strip=True)  return info

主循环建议打印进度:[当前条/总条] 日期 标题前若干字。单条失败不要整批中断,记日志后继续;正文过长时可截断并注明“详见链接”,避免 Excel 单元格写爆。

五、第三步:按时间线导出 Excel

建议固定列顺序,冻结首行,方便筛选:

发布日期
成文日期
政策名称
出文单位
发文字号
主题分类
索引号
正文内容
链接
cols = [  "发行日期", "成文日期", "政策名称", "出文单位", "发文字号",  "主题分类", "索引号", "正文内容", "链接",  ]  df = pd.DataFrame(records, columns=cols)  with pd.ExcelWriter(OUT_FILE, engine="openpyxl") as writer:  df.to_excel(writer, index=False, sheet_name="农业政策_近十年")  ws = writer.sheets["农业政策_近十年"]  for col, w in {  "A": 12, "B": 12, "C": 42, "D": 14, "E": 20,  "F": 32, "G": 20, "H": 55, "I": 40,  }.items():  ws.column_dimensions[col].width = w  ws.freeze_panes = "A2"print(f"完成:{len(df)} 条,正文成功 {sum(1 for r in records if r['正文内容'])} 条")  print(f"文件:{OUT_FILE}")

落盘后先做三件事:看时间线首尾是否合理;抽 5–10 条点开“链接”核对标题与日期;看“正文成功”条数是否接近总数。这三步比再写一百行代码更重要。

六、写进论文前,守住四条底线

  1. 礼貌抓取。 搜索翻页与详情请求都加间隔,控制总量,避免短时间高频访问。

  2. 保留出处。 表格必须留下原始链接、发布日期、发文字号(若有),便于复核与规范引用。

  3. 抽样核验。 随机对照官网,确认没有串行、截断或日期解析错误。

  4. 合规使用。 公开政策文本可用于学术整理与分析;批量下载后仍应遵守网站使用条款,不作未经授权的再分发或商用包装。

爬虫只解决“材料在桌面上”。论文真正被评价的,是政策总体如何界定、如何编码、如何接到研究问题上。

最新文章

随机文章