资讯详情

咸阳工商招标信息抓取实战:从数据源分析到合规爬虫方案

📅 2026/10/16 5:30:24 | 华诺云谱 👁 阅读
咸阳工商招标信息抓取实战:从数据源分析到合规爬虫方案
1. 从咸阳工商招标信息抓取这个需求说起第一次看到咸阳工商招标信息抓取这个标题我脑子里蹦出来的第一个念头不是怎么写爬虫而是这事儿到底值不值得做。招标信息这东西本质上是一种时效性极强、分散度极高、结构化程度极低的公开数据。它散落在各个政府采购网、公共资源交易中心、企业官网的角落里格式五花八门有的用表格有的用PDF有的干脆就是一张图片。你想把这些信息汇总起来做商机监控、做竞品分析、做投标决策辅助手工翻页复制粘贴显然不现实于是抓取就成了一个绕不开的环节。但我要先把话说在前头招标信息抓取这件事技术难度不高合规门槛却不低。很多人一上来就想着我写个脚本把数据全薅下来结果要么被目标站点封了IP要么抓下来的数据缺胳膊少腿没法用要么压根没搞清楚哪些数据是允许批量获取的。所以这篇内容我不打算只给你一段爬虫代码就完事而是想把这几年在类似项目里踩过的坑、总结的方法、以及真正能跑通的方案从头到尾捋一遍。这篇文章适合三类人看第一类是有一定编程基础、想自己动手做招标信息聚合的开发者第二类是负责市场或商务、需要监控招标动态但不懂技术的从业者你们可以重点看数据源分析和字段设计部分第三类是做数据服务、想把招标信息做成产品的团队合规和反爬策略那几节对你们最有用。我会尽量用大白话把原理讲清楚同时给出可以直接参考的代码和配置让你看完就能动手试。2. 先搞清楚数据从哪来咸阳地区招标信息的主要来源盘点2.1 公共资源交易平台是主战场咸阳地区的招标信息最核心的来源是公共资源交易平台。这类平台通常由官方运营发布的内容涵盖工程建设、政府采购、土地出让、产权交易等多个类别。它的特点是权威性高、更新及时、覆盖面广但页面结构往往比较老旧很多还是十几年前的技术栈表格嵌套表格分页用POST请求给抓取带来不少麻烦。我实际接触过的几个平台列表页普遍采用标题发布时间地区类别的简单结构详情页则包含公告正文、附件下载链接、预算金额、投标截止时间等关键字段。这里有个经验列表页能拿到的字段尽量在列表页拿完不要每个条目都去请求详情页。因为详情页请求量大最容易触发限流而列表页通常一页就能拿到二三十条记录的标题和时间性价比高得多。2.2 政府采购网与行业主管部门网站除了交易平台政府采购网也是重要来源。这类站点的信息分类更细有的按采购单位分有的按品目分。咸阳本地的采购公告有时候会同时出现在省级平台和市级平台上存在重复发布的情况。这就引出一个关键问题去重。我一般会用标题发布时间采购单位做联合唯一键因为单纯用标题去重会误杀不同项目标题相似的情况太常见了。行业主管部门网站则更垂直比如住建、交通、水利这些部门会发布本行业的招标信息。这类站点的信息量不大但专业性强如果你做的是垂直领域的商机监控这些源反而比综合平台更有价值。2.3 企业官网与第三方聚合平台有些大型企业会把自己的招标信息发布在官网的招标采购栏目里。这类页面的结构千差万别有的用CMS系统生成规律性强有的就是编辑手动传的HTML毫无规律可言。对于后者我通常建议放弃全自动抓取改用半自动的方式——脚本负责监控页面变化并推送提醒人工确认后再录入。第三方聚合平台也值得关注它们本身已经把多个源的数据汇总了你抓它们相当于二次加工。但这里要特别注意合规问题聚合平台的数据往往有自己的整理加工成分直接批量抓取风险较高建议只做小范围的监控和人工参考。数据源类型权威性更新频率抓取难度推荐优先级公共资源交易平台高实时中高最高政府采购网高每日中高行业主管部门网站高不定期低中企业官网中不定期高低第三方聚合平台中每日低谨慎3. 抓取方案选型为什么我没有一上来就写Scrapy3.1 请求库的选择逻辑很多人做爬虫第一反应是上Scrapy框架觉得专业。但我做这类招标信息抓取首选往往是requests加BeautifulSoup的组合原因很简单招标站点的页面结构相对固定不需要复杂的调度和分布式Scrapy的很多能力用不上反而增加了调试成本。requests负责发请求BeautifulSoup负责解析几十行代码就能跑通一个源维护起来也直观。当然如果你的目标是同时监控几十个源需要定时调度、失败重试、并发控制那Scrapy或者更轻量的httpx加asyncio就更合适。我的判断标准是源的数量超过10个或者需要7x24小时运行就上框架否则脚本足够。3.2 解析方式CSS选择器还是XPath解析HTML我一般用CSS选择器因为可读性好写起来快。但招标站点的HTML经常不规范标签闭合混乱这时候XPath的容错性反而更强。我的做法是先用CSS选择器试搞不定的再用XPath兜底。另外lxml解析器比html.parser快不少处理大页面时优势明显建议优先用lxml。这里有个细节很多招标列表页的表格是用table套tr套td的经典结构但有的站点会在td里再嵌一层a标签。你提取链接的时候要取a的href属性而不是td的文本。我见过不少人直接取td的text结果拿到的是标题文字链接丢了还得回头重新解析。3.3 编码问题GBK还是UTF-8招标站点里老平台用GBK编码的比例相当高。如果你用requests直接取response.text遇到GBK页面会乱码。正确的做法是先看response.encoding如果站点声明的是GBK就手动设置response.encoding gbk或者直接用response.content.decode(gbk, errorsignore)。我一般会在请求头里带上Accept-Charset但说实话很多老站点根本不认这个头还是得靠代码里判断。import requests from bs4 import BeautifulSoup def fetch_page(url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept-Charset: utf-8, gbk } resp requests.get(url, headersheaders, timeout15) if resp.encoding ISO-8859-1: # 很多站点不声明编码requests会默认ISO-8859-1 resp.encoding resp.apparent_encoding return resp.text上面这段代码里apparent_encoding是chardet库的封装能自动猜测编码对付那些不声明编码的站点很管用。但要注意猜测不是100%准确遇到乱码还是得手动指定。4. 字段设计与数据清洗抓下来只是第一步4.1 招标信息到底要抓哪些字段抓取之前先想清楚你要什么。我见过太多人抓了一堆数据最后发现关键字段没抓或者抓了一堆用不上的垃圾字段。招标信息的核心字段我总结下来有这么几类标识类项目编号、公告标题、公告类型招标公告/中标公告/变更公告时间类发布时间、报名截止时间、投标截止时间、开标时间主体类采购单位、代理机构、项目联系人内容类预算金额、项目概况、资质要求链接类详情页URL、附件下载URL其中时间类字段最容易出问题。有的站点只写2024年3月15日有的写2024-03-15 09:30还有的写自公告发布之日起5个工作日。最后这种相对时间你必须结合发布时间来换算否则数据没法用。我的做法是统一转成ISO 8601格式YYYY-MM-DD HH:MM:SS相对时间用发布时间加偏移量计算。4.2 金额字段的清洗陷阱预算金额的清洗是个大坑。同样是100万有的写100万元有的写1,000,000.00有的写壹佰万元整。更麻烦的是有的公告里金额是最高限价有的是预算金额含义不同不能混为一谈。我一般会做两级处理先正则提取数字再根据单位词万/亿/元做换算最后保留原始文本备查。import re def parse_amount(text): if not text: return None, None # 提取数字和单位 match re.search(r([\d,.])\s*(万元|万|亿元|亿|元)?, text) if not match: return None, text num_str match.group(1).replace(,, ).replace(, ) unit match.group(2) or 元 try: num float(num_str) except ValueError: return None, text multiplier {万元: 10000, 万: 10000, 亿元: 100000000, 亿: 100000000, 元: 1} return num * multiplier.get(unit, 1), text这段代码保留了原始文本方便后续人工核对。我强烈建议永远保留原始字段因为清洗规则可能出错保留原始数据才有回溯的可能。4.3 去重策略别让同一条公告出现三次前面提到过同一条招标公告可能在多个平台发布。去重不能只看标题因为标题可能被不同平台编辑过。我的策略是三级去重第一级用项目编号如果编号存在且一致直接判定重复第二级用标题发布时间的哈希第三级用采购单位预算金额截止时间的组合。三级都过不了的才认为是新记录。这里有个经验去重要在入库时做不要在抓取时做。因为抓取时你只有当前批次的数据没法跟历史数据比对。用数据库的唯一索引来兜底是最稳妥的做法。5. 反爬应对与请求策略怎么抓得稳、抓得久5.1 请求频率控制是底线不管目标站点有没有反爬控制请求频率都是基本素养。我一般把单站点的请求间隔设在3到5秒高峰期比如工作日上午适当拉长到8秒。有人觉得这样太慢但你想想你抓的是招标信息不是股票行情晚几分钟拿到数据不影响决策但把人家站点搞挂了那就是另一回事了。实现上最简单的做法是time.sleep()但这样会阻塞整个线程。如果用了多线程建议用令牌桶或者信号量来控制。我常用的是一个简单的限速装饰器import time from functools import wraps def rate_limit(interval3): def decorator(func): last_called [0.0] wraps(func) def wrapper(*args, **kwargs): elapsed time.time() - last_called[0] wait interval - elapsed if wait 0: time.sleep(wait) result func(*args, **kwargs) last_called[0] time.time() return result return wrapper return decorator这个装饰器保证同一个函数两次调用之间至少间隔interval秒简单有效。5.2 User-Agent与请求头伪装招标站点一般不会做太复杂的反爬但基本的User-Agent检查还是有的。我建议准备一组常见的浏览器UA随机轮换同时带上Accept、Accept-Language、Referer这些常规头。Referer尤其重要有些站点会检查请求来源直接从列表页跳详情页的请求Referer设成列表页URL通过率会高很多。但我要提醒一句伪装请求头是为了正常访问不是为了绕过访问控制。如果站点明确要求登录才能查看那就老老实实走登录流程或者放弃这个源。强行绕过登录限制性质就变了。5.3 遇到验证码怎么办招标站点出现验证码的情况不算多但偶尔会遇到。我的处理原则是能绕就绕绕不过就降级。所谓绕是指看看验证码是不是只在特定条件下触发比如请求太频繁、IP异常。如果是那就降低频率、换时间段再试。所谓降级是指放弃自动抓取改成人工监控加手动录入。我不建议去搞验证码识别一来技术成本高二来容易踩线。招标信息是公开数据但公开不等于可以无限制批量获取这个边界要心里有数。5.4 失败重试与断点续抓网络请求失败是常态尤其是抓取大量页面的时候。我的做法是每个请求失败后重试3次每次间隔指数增长比如1秒、2秒、4秒。如果3次都失败就把这条记录写入失败队列等整批抓取结束后再统一重试。这样既不会因为个别失败卡住整体进度也不会漏掉数据。断点续抓也很重要。我一般会在数据库里记录每个源的最后抓取时间和最后抓取页码下次启动时从断点继续。这样即使程序中途挂了重启后也不用从头再来。6. 数据存储与后续利用抓完不是终点6.1 存哪里SQLite还是MySQL小规模抓取SQLite足够用一个文件搞定部署简单。但如果数据量上了十万条或者需要多进程同时写入就得换MySQL或者PostgreSQL。我一般开发阶段用SQLite生产环境用MySQL表结构保持一致迁移成本很低。表结构设计上我建议原始表和清洗表分开。原始表存抓取到的原始文本清洗表存结构化后的字段。这样清洗规则变了可以重新跑一遍清洗不用重新抓取。CREATE TABLE tender_raw ( id INTEGER PRIMARY KEY AUTOINCREMENT, source VARCHAR(50), url VARCHAR(500) UNIQUE, raw_html TEXT, fetch_time DATETIME, status VARCHAR(20) DEFAULT pending ); CREATE TABLE tender_clean ( id INTEGER PRIMARY KEY AUTOINCREMENT, raw_id INTEGER, project_code VARCHAR(100), title VARCHAR(500), publish_time DATETIME, deadline DATETIME, budget DECIMAL(15,2), purchaser VARCHAR(200), category VARCHAR(50), UNIQUE KEY uk_project (project_code, publish_time) );6.2 增量抓取与变更监控招标信息有个特点公告会变更。今天发的招标公告明天可能发个更正公告改了截止时间或者预算金额。如果你只抓一次就会漏掉变更。我的做法是对已抓取的URL定期回访比对内容哈希发现变化就更新记录并标记变更类型。回访频率不用太高一周一次足够因为大部分公告发布后不会频繁改动。6.3 数据利用的几个方向抓下来的数据能干什么我见过几种典型用法一是商机推送根据关键词匹配把相关招标信息推送给业务人员二是竞品分析看某家公司最近在投哪些标、中标价格区间是多少三是市场趋势分析统计某个品类的招标数量和预算规模变化。这些用法对数据质量的要求不同商机推送要求时效性高竞品分析要求字段全趋势分析要求数据量大。你在设计抓取方案时最好先想清楚数据给谁用、怎么用再决定抓什么、抓多细。7. 合规边界与实操中的几条红线7.1 公开数据不等于可以随意抓招标信息是公开的这一点没错。但公开意味着任何人都可以正常访问不意味着你可以用脚本高频批量获取。我的判断标准是你的抓取行为是否会影响站点的正常服务。如果因为你的抓取其他用户访问变慢了那就有问题。所以频率控制不是可选项是必选项。另外不要抓取需要登录才能查看的内容。有些平台的详细信息要注册登录后才能看这种就别碰了。还有不要绕过robots.txt。虽然robots.txt不是法律文件但它代表了站点运营者的意愿尊重它是基本的行业规范。7.2 数据使用也要注意边界抓下来的数据自己用和对外提供性质不一样。自己用做内部决策参考风险较低如果要把数据打包卖或者公开提供就要考虑数据的再分发是否合规。我的建议是抓取的数据只用于内部参考不对外批量分发。如果要做产品最好基于数据做加工分析提供分析结果而不是原始数据。7.3 遇到投诉或警告怎么办如果你收到站点的警告或者投诉第一时间停止抓取并检查自己的行为是否越界。不要抱着我只是抓公开数据的心态硬扛。招标信息抓取这个领域技术不是门槛合规意识才是。我见过太多技术很牛但合规意识淡薄的案例最后都走不远。8. 几个实际踩过的坑和应对经验8.1 分页参数是加密的有个站点的分页参数不是简单的page1、page2而是一串看起来像Base64的字符串。我一开始以为是加密后来发现是把页码和当前时间戳拼在一起做了简单编码。这种设计在老站点里很常见目的是防止直接改URL翻页。应对方法就是先正常访问第一页从页面里提取下一页的链接而不是自己拼URL。这样虽然慢一点但稳定可靠。8.2 详情页的附件才是关键很多招标公告的正文里只有一句话详见附件真正的项目概况、资质要求、评分标准全在附件里。附件格式有PDF、Word、Excel甚至还有压缩包。如果你只抓正文信息量几乎为零。我的做法是把附件下载链接也抓下来单独存一张表后续用pdfplumber或者python-docx解析。但要注意附件下载往往有额外的权限校验有的需要Referer有的需要Cookie得具体站点具体分析。8.3 时间字段的时区问题招标公告里的时间默认都是北京时间。但如果你服务器用的是UTC时间存库的时候就会差8小时。我一开始没注意这个导致截止时间判断全错了。后来统一在入库前做时区转换所有时间字段都转成北京时间再存显示的时候也按北京时间显示避免混乱。8.4 页面结构突然改版这是最让人头疼的情况。你辛辛苦苦写好的解析规则站点一改版全废了。我的应对策略是把解析规则配置化每个源对应一个配置文件里面写清楚列表页的选择器、详情页的选择器、字段映射关系。改版的时候只需要改配置不用改代码。另外加一个监控告警如果某个源连续多次抓取到的记录数为零就发提醒这样能第一时间发现改版。# 配置化解析示例 SOURCE_CONFIG { source_a: { list_url: https://example.com/list?page{page}, list_selector: table.list tr, title_selector: td:nth-child(2) a, time_selector: td:nth-child(3), link_attr: href, encoding: gbk } }这种配置化的写法虽然前期多花点时间但后期维护成本低很多。尤其是当你监控的源超过5个以后配置化的优势就非常明显了。8.5 抓取任务被意外中断程序跑着跑着挂了或者服务器重启了这是常有的事。如果没有断点续抓机制就得从头再来。我的做法是每抓完一页就更新一次进度把当前源的当前页码写进数据库。重启后先读进度从上次的页码继续。另外用日志记录每一次请求的结果成功还是失败、耗时多少、返回状态码是什么这些信息在排查问题时非常有用。9. 关于这套方案的实际效果和后续扩展这套方案我在几个类似项目里跑过单源日均抓取量在几百到几千条之间稳定性可以接受。最关键的不是技术多先进而是把合规、频率控制、失败处理这些脏活累活做扎实。很多人追求一天抓十万条的爽感但招标信息这个场景数据质量比数量重要得多。一条准确的截止时间比一万条残缺的记录有价值。后续如果要扩展我建议从两个方向入手一是增加数据源把咸阳周边地区的招标信息也纳入监控扩大商机覆盖面二是做数据加工比如用关键词提取做自动分类用历史数据做中标价格预测。但这些都建立在基础抓取稳定、数据质量可靠的前提下。基础不牢上层建筑都是空中楼阁。最后分享一个我自己的习惯每次新增一个数据源先手动抓20条逐条核对字段是否准确再放开批量抓取。这个习惯帮我省了很多返工的时间。招标信息抓取这件事慢就是快稳就是省。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑