2026-10-27 · 操作笔记

把四省市专精特新公示名单抓下来:22,960 条,以及我踩的三个口径坑

作者:木羽GEO(深圳市茹木得易科技有限公司)发布于 2026-10-27最后更新 2026-10-27

起因很简单:我想知道「权威机构发布的名单」这类公开信源,实际能用到什么程度。挑了上海、江苏、安徽、广东四省市 2025 年度的省级专精特新中小企业公示名单,全部抓下来,去重之后 22,960 条。

这一篇记录抓取过程和三个口径坑。结论放在最前面:公示文本里能稳定拿到的字段只有两个——企业名称、所属批次。 字段集决定了它能用来做什么,这个限制比数据量大不大重要得多。

一、数据源怎么找

公示名单挂在各省工信厅或经信委官网上,发布形式不统一。这次遇到的三种:

江苏和安徽是公告页挂附件,附件多为 xls 或 xlsx,比较好处理。

上海分四批发布,每批一个页面,附件有 xls 也有 pdf。

广东是省厅公示加深圳单列公示,深圳那份在市中小企业服务局,需要单独抓。

找文件的办法很笨但有效:在站内搜「专精特新中小企业 公示 2025」,按发布时间排序,逐条看附件后缀。四个省市加起来二十来个文件,手工过一遍比写爬虫快。

二、解析

附件格式不统一,得分开处理。

xls/xlsx 直接用 pandas:

import pandas as pd

def read_list(path):
    df = pd.read_excel(path, dtype=str)
    df = df.dropna(how="all")
    return df

pdf 用 pdfplumber,按行取文本再切列:

import pdfplumber

def read_pdf(path):
    rows = []
    with pdfplumber.open(path) as pdf:
        for page in pdf.pages:
            table = page.extract_table()
            if table:
                rows.extend(table)
    return rows

pdf 的麻烦在于表格线和合并单元格,跨页的表头会重复出现,需要在清洗阶段单独处理。这份数据里 pdf 占比不高,我最后是人工抽了一份对照,确认抽取结果和原件一致才继续往下走。

三、去重与清洗

按企业名称去重:

import re

def norm(name: str) -> str:
    name = name.replace(" ", "").replace("(", "(").replace(")", ")")
    name = re.sub(r"[*\s]", "", name)
    return name.strip()

df["key"] = df["企业名称"].map(norm)
df = df.drop_duplicates(subset="key")

全角半角括号、多余空格是最常见的重复来源。这一步做完,四省市合计 22,960 条。

我没有做工商核验。也就是说,重名企业和登记信息变更的情况没有被识别出来,这是这份数据的一个已知缺陷,后面用到时得记着。

四、三个口径坑

坑一:年度批次不等于存量

这是最容易出错的一处。我统计的是 2025 这一年公示出来的批次,广东 3,758 条;而广东省工信厅 2026 年 9 月的政策解读口径是「累计培育专精特新中小企业超 3 万家」。

两个数字都对,回答的问题不同:一个是当年新增认定,一个是累计培育。写分析时如果把两者混着用,或者直接拿其中一个否定另一个,结论就站不住。

我最后的处理是:所有对外输出都明确标注「2025 年度公示批次」,并在提到存量时单独注明来源与时间。

坑二:地区字段来自公示文件,不是工商注册地

深圳单列公示。如果只按省厅文件计数,广东会少掉最大的一块——深圳 2,535 条,占广东的六成以上。

我按公示文件的归属合并,广东合计 3,758 条(含深圳 2,535)。这个口径下「地区」字段表示的是「谁发布的」,不完全等于企业注册地。

坑三:城市字段是推断出来的

公示文本通常只有企业名称和批次,没有注册地。城市只能从企业名称里的地名推断:

CITY_HINTS = ["上海", "深圳", "苏州", "南京", "无锡", "常州",
              "东莞", "合肥", "芜湖", "佛山"]

def guess_city(name: str):
    for city in CITY_HINTS:
        if city in name:
            return city
    return None

结果:22,960 条里有 6,385 条推断不出,留空。占四分之一还多。

这个比例意味着城市分布只能看趋势,不能当注册地口径用。我在输出时保留了「城市分布仅作趋势参考」的标注——推断字段和原始字段必须区分开,否则后面的所有分析都建立在沙子上面。

五、抓完之后,这份数据能用来做什么

先说不能做什么。

公示文本里能稳定拿到的字段只有两个:企业名称、所属批次,部分文件带地市。没有官网地址、没有主营产品、没有联系人、没有技术方向、没有统一社会信用代码。

所以它能证明的只有一件事:这家公司存在,且在某年被认定为省级专精特新。

它能用来做的是核验:拿一份企业名单跟它比对,确认哪些企业在名单里、是哪一批。这个用途很具体,也够用。

它做不到的是描述能力。想知道这家企业做什么、能做到什么精度、交期多久、给谁供过货,公示文件上一个字都没有——这些得去别处找,或者由企业自己写出来。

六、一句小结

抓数据之前先想清楚字段集。22,960 条听起来不小,但每条只有两个可用字段,它能支撑的结论就那么多。

我见过不少分析把「名单上有多少家企业」直接当成「这个行业有多少能干的玩家」来用,中间差的那一步就是字段集的限制。数据量大不等于信息量大,这两件事在数据抓取这个行当里经常被搞混。

下一轮我打算换个方向:拿固定问题集去问一批 AI 平台,看答案里出现的名字和这份名单的重合度有多高。那组数据得等跑完再写。