FEATURED · 精选文章

数学建模竞赛数据抓取实战:Python Requests+BeautifulSoup快速获取关键数据

发布时间 / 2026/8/29 12:20:18
来源 / 创域科博编辑部
栏目 / 资讯中心
数学建模竞赛数据抓取实战:Python Requests+BeautifulSoup快速获取关键数据 1. 项目概述当数学建模遇上Python数据抓取如果你正在准备数学建模竞赛无论是国赛、美赛还是亚太杯你肯定遇到过这样的困境题目给了一个宏大的背景比如“城市交通拥堵分析”、“电商平台用户行为研究”但数据呢往往只有寥寥几行描述或者干脆让你“自行收集相关数据”。2019年的国赛C题“机场的出租车问题”就是一个典型它需要你分析机场出租车的排队、载客策略但数据从哪来航班时刻、出租车流量、乘客等待时间这些都不是现成的。这时候掌握一手数据抓取能力就成了拉开队伍差距的关键。这个项目就是围绕“用Python为数学建模抓取数据”这个核心需求展开的。简单来说它解决的是数学建模中“巧妇难为无米之炊”的痛点。你不是在写一个通用的、商业级的爬虫系统而是在竞赛有限的时间内通常是3-4天针对一个具体、明确的问题快速、精准、合法地获取到支撑你模型建立与求解的关键数据集。这要求你的代码必须快、准、稳快速开发精准定位数据稳定运行不出错。整个过程更像是一次战术性的“数据特种作战”而非战略性的“平台建设”。接下来我会结合我多次带队参赛和实际开发的经验拆解从思路到实现的每一个环节并分享那些在官方教程里绝不会写的“踩坑”实录。2. 核心思路与工具选型为什么是PythonRequestsBeautifulSoup在数学建模的语境下选择技术栈效率和上手速度是第一位的。你不可能花两天时间去搭建一个复杂的Scrapy分布式框架虽然它很强大。我们的目标是用最小的学习成本实现最直接的抓取目标。2.1 核心工具链解析我首推RequestsBeautifulSoup4Pandas这个黄金组合。这是经过无数次实战检验的“老兵油子”套装。Requests库负责网络通信也就是“伸手去要数据”。它的API设计极其人性化requests.get(url, headersheaders, paramsparams)几乎能覆盖90%的静态网页抓取场景。对于需要登录的网站它也能通过Session对象优雅地管理Cookies。在建模竞赛中你遇到的绝大部分数据源如政府统计网站、公开的学术数据集页面、企业发布的报告PDF链接页都可以用它搞定。BeautifulSoup4库负责解析HTML/XML文档也就是“从拿回来的网页里找到你要的数据”。它支持多种解析器如lxml,html.parser能让你用类似soup.find(‘div’, class_‘data-table’).find_all(‘tr’)这样直观的语法来定位元素。相比于正则表达式它的可读性和容错性要好得多这对于在高压竞赛中调试代码至关重要。Pandas库虽然它主要是一个数据分析库但在数据抓取环节也扮演着“清道夫”和“搬运工”的角色。你可以用pd.read_html()尝试直接解析网页中的表格虽然成功率取决于表格的规范程度更重要的是抓取下来的零散数据列表、字典可以非常方便地用pd.DataFrame()转换成结构化的DataFrame然后一键导出为data.csv或data.xlsx无缝对接后续的建模分析如Matplotlib绘图、Statsmodels统计分析。2.2 为什么不是Scrapy或Selenium这是一个关键的选型决策。Scrapy是一个异步框架适合大规模、结构固定的网站抓取但学习曲线较陡且调试起来不如单脚本直观。在建模竞赛中你的目标网站可能就一两个页面结构也不复杂用Scrapy有点“杀鸡用牛刀”反而增加了项目结构的复杂度。Selenium是浏览器自动化工具能处理JavaScript动态渲染的页面。如果你的数据确实是通过AJAX加载、在页面源代码里找不到的那么Selenium是必要的。但它的代价是速度慢和依赖浏览器驱动。每抓取一个页面都要启动一个浏览器实例对于成百上千页的数据抓取来说是灾难。因此我的原则是优先尝试用Requests模拟AJAX请求。通过浏览器的开发者工具F12查看“网络”(Network)选项卡中的XHR/Fetch请求找到真正的数据接口通常是返回JSON格式的API然后用Requests去调用这个接口效率能提升几十倍。只有在无法逆向接口、且数据量不大的情况下才考虑使用Selenium。实操心得在竞赛开始前花1-2个小时用RequestsBeautifulSoup写一个抓取某个新闻网站标题的小脚本并成功保存到CSV文件。这个“最小可行产品”能极大地增强你的信心并确保你的Python环境是没问题的。避免在赛程中才第一次配置环境那会非常被动。3. 完整抓取流程拆解与实战让我们以一个虚构但非常贴近实际赛题的场景为例“分析某城市公共自行车站点的使用规律”。赛题描述可能提到“数据来源于本市公共自行车服务平台”。你需要去该平台的官网抓取各个站点的实时状态可用车辆数、空桩数历史数据。3.1 目标分析与URL规划第一步永远不是写代码而是“人肉侦察”。打开目标网站找到包含目标数据的页面。比如站点列表可能在http://www.xxx-bike.com/stations每个站点的详情页可能是http://www.xxx-bike.com/station/1001。观察URL规律1001可能就是站点ID。接着查看详情页的数据是直接嵌入在HTML里还是通过一个单独的接口加载。按F12打开开发者工具刷新页面在“网络”里寻找类似getStationDetail?stationId1001的请求其响应往往是干净的JSON。如果能找到这个API你的工作就完成了80%。3.2 请求头Headers与反爬虫基础策略直接使用requests.get(url)可能会被网站拒绝返回403错误或毫无意义的HTML。这是因为网站会检查请求头尤其是User-Agent。你需要让你的Python脚本看起来像一个普通的浏览器。import requests 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‘, ’Accept‘: ’text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8‘, ’Accept-Language‘: ’zh-CN,zh;q0.9,en;q0.8‘, } response requests.get(’http://www.xxx-bike.com/stations‘, headersheaders)除了User-Agent有些网站还会检查Referer请求来源页或使用Cookies来维持会话。对于简单的公开数据设置一个合理的User-Agent通常就够了。务必遵守网站的robots.txt协议通常在网站根目录如http://www.xxx-bike.com/robots.txt这是法律和道德的底线在学术竞赛中尤为重要。3.3 数据解析与提取假设我们找到了站点列表APIhttp://www.xxx-bike.com/api/stations返回JSON。而每个站点的详情需要再调用http://www.xxx-bike.com/api/station/[id]/detail。import requests import pandas as pd import time # 1. 获取所有站点基本信息 list_url ’http://www.xxx-bike.com/api/stations‘ resp requests.get(list_url, headersheaders) station_list resp.json() # 假设返回的是JSON列表 all_data [] for station in station_list: station_id station[’id‘] station_name station[’name‘] # 2. 获取每个站点的详细数据 detail_url f’http://www.xxx-bike.com/api/station/{station_id}/detail‘ detail_resp requests.get(detail_url, headersheaders) detail_data detail_resp.json() # 3. 合并数据 record { ’station_id‘: station_id, ’station_name‘: station_name, ’bikes_available‘: detail_data.get(’bikes‘, 0), ’docks_available‘: detail_data.get(’docks‘, 0), ’update_time‘: detail_data.get(’timestamp‘, ’’), } all_data.append(record) # 4. 礼貌性延迟避免请求过快 time.sleep(0.5) # 每次请求后暂停0.5秒 # 5. 转换为DataFrame并保存 df pd.DataFrame(all_data) df.to_csv(’bike_station_data.csv‘, indexFalse, encoding’utf-8-sig‘) # 用utf-8-sig避免Excel打开中文乱码 print(f“成功抓取 {len(df)} 个站点的数据。”)3.4 数据清洗与初步整理抓取下来的数据往往不是完美的。pd.read_csv()之后你需要立刻进行以下检查缺失值查看df.isnull().sum()。对于数值列可以考虑用中位数或均值填充对于时间列可能需要向前或向后填充或者根据你的模型决定是否删除整行。异常值比如“可用车辆数”大于“总桩数”这显然不合理。可以用df.describe()查看分布或用箱线图可视化然后根据业务逻辑如可用车辆数不可能为负进行过滤或修正。格式统一时间戳可能是一串数字Unix时间戳或字符串。使用pd.to_datetime()进行统一转换这是后续做时间序列分析的基础。去重检查是否有完全重复的记录df.duplicated().sum()。在建模竞赛中数据清洗的过程和逻辑本身就可以写入论文作为你数据处理能力的一部分。4. 高级技巧与常见问题突围掌握了基础流程你可能会遇到一些更棘手的情况。下面这些技巧能帮你节省大量时间。4.1 处理动态加载AJAX数据如前所述优先找API。在开发者工具的“网络”选项卡中筛选XHR或Fetch请求仔细查看“预览”(Preview)标签页。找到返回目标数据的那个请求然后复制它的“cURL”命令。有很多在线工具可以把cURL转换成Python的Requests代码这能帮你快速生成携带正确Headers和参数的请求代码。如果找不到清晰的API或者API参数被复杂加密较少见再考虑Selenium。from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import pandas as pd driver webdriver.Chrome() # 确保已下载对应版本的ChromeDriver并放在PATH中 driver.get(“目标页面URL”) # 等待某个标志性元素出现确保页面加载完成 try: element WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, “data-table”)) ) # 开始解析页面 html driver.page_source # 接下来可以用BeautifulSoup解析html finally: driver.quit()4.2 应对IP封锁与请求限制对于数学建模竞赛你抓取的数据量通常不会大到触发IP封锁。但如果需要高频请求最简单的策略是增加延迟在循环请求中time.sleep(random.uniform(1, 3))加入随机性模拟人工操作。使用代理IP在竞赛环境下免费代理IP不稳定且速度慢不推荐。更实际的方法是如果学校有提供不同的网络出口如校园网、实验室网络可以尝试切换。或者和队友分工从不同的网络环境如图书馆、宿舍同时运行脚本的不同部分。分解任务如果抓取1000个页面不要用一个脚本从头跑到尾。可以分成10个CSV文件分时、分段抓取即使中途中断损失也较小。4.3 数据存储与版本管理不要把所有数据都塞进一个巨大的列表最后再保存。我习惯每抓取成功50或100条记录就追加写入一次文件。这样即使程序崩溃或网络中断之前的数据也不会丢失。# 使用追加模式写入CSV if not os.path.exists(’output.csv‘): df_head.to_csv(’output.csv‘, mode’w‘, headerTrue, indexFalse) else: df_chunk.to_csv(’output.csv‘, mode’a‘, headerFalse, indexFalse)另外务必做好数据备份和版本注释。在竞赛文件夹里建立data/raw/原始数据、data/processed/清洗后数据这样的目录。每次运行抓取脚本在文件名或文件夹名中加入日期时间戳如bike_data_20231027_1430.csv。在论文中需要明确说明数据来源和获取时间这体现了工作的严谨性。5. 从数据到模型抓取工作的闭环数据抓取不是终点而是建模的起点。抓取到的数据如何服务于你的模型这里有几个结合点5.1 特征工程直接来源于抓取逻辑你在设计抓取脚本时其实已经在做特征工程了。例如抓取公共自行车站点数据时你不仅抓了车辆数还抓了站点的经纬度lat,lng。有了经纬度你就可以在后续计算站点之间的距离矩阵或者结合地图API获取站点周边的POI兴趣点如地铁站、商场信息这些都可能成为影响站点使用率的关键特征。你的抓取脚本可以设计成同时调用高德或百度地图的逆地理编码API将坐标转换为地址和商圈类型。5.2 时间序列数据的抓取策略很多建模问题涉及时间序列分析如预测未来流量。你需要的数据不是某个时间点的快照而是一段时间内的连续观测。这就要求你的抓取脚本能定时运行。在竞赛环境下你可以写一个简单的循环搭配time.sleep(interval)来实现。例如每隔10分钟抓取一次实时数据持续24小时。注意要处理好请求失败的重试机制并在本地记录每次抓取的时间戳。import schedule import time def job(): print(“开始抓取数据...”) # 这里是你的抓取函数 # ... print(f“抓取完成时间{time.strftime(’%Y-%m-%d %H:%M:%S‘)}”) # 每10分钟执行一次 schedule.every(10).minutes.do(job) while True: schedule.run_pending() time.sleep(1) # 可以设置一个总时长比如24小时后跳出循环5.3 数据验证与论文呈现抓取到的数据一定要进行合理性验证。比如抓取的各站点车辆总数是否大致符合该城市公开报道的投放总量某个站点的数据在24小时内是否会出现断崖式变化可能是抓取错误这些验证过程可以成为你论文中“数据预处理”部分的重要内容展示你对数据质量的把控。在论文中呈现这部分工作时不要只写“我们使用Python爬虫获取了数据”。应该简要说明数据来源具体的网站或API地址如果公开。抓取工具Python, Requests库等。抓取对象具体是哪些字段如站点ID、名称、经纬度、可用车辆数、时间戳。抓取周期与频率何时开始何时结束多久抓取一次。数据规模最终获得了多少条记录多少MB的数据。遇到的挑战与处理例如遇到了反爬机制通过添加请求头和设置延迟解决某个时间段数据缺失采用了插值法补充。这能极大地提升论文的可靠性和工作量感。6. 避坑指南与竞赛实战心得最后分享一些只有真正在竞赛中摸爬滚打过才能总结出的经验。6.1 环境与依赖管理这是第一个大坑。不要在竞赛当天才在电脑上装Python和库。赛前一周务必在比赛用的所有电脑上配置好统一的开发环境。强烈推荐使用conda或venv创建虚拟环境并用pip freeze requirements.txt导出依赖列表。这样在任何一台电脑上都能通过pip install -r requirements.txt快速复现环境。把requirements.txt文件也放在团队的项目文件夹里。6.2 代码结构与团队协作你的抓取脚本不应该是一个几百行揉在一起的.py文件。至少应该分成几个模块config.py存放常量如目标URL、请求头、文件保存路径、数据库连接信息如果用的话。spider.py核心的抓取和解析函数。utils.py存放工具函数如处理时间的函数、随机延迟函数、日志记录函数。main.py主程序入口负责调度和流程控制。这样分工清晰队友也容易看懂和修改。使用Git进行版本控制哪怕只是本地仓库是专业的表现能有效避免“谁改坏了代码”的纠纷。6.3 法律与道德底线再强调数学建模竞赛是学术活动必须恪守学术规范。绝对不要尝试抓取个人隐私数据、受版权严格保护的数据或通过攻击手段获取数据。只抓取公开的、非敏感的信息。如果网站明确声明禁止抓取在robots.txt或用户协议中请寻找替代数据源。你的论文可能会被公示任何不当的数据获取方式都可能带来严重后果。6.4 制定备选方案不要把所有希望寄托在一个数据源上。在分析赛题、规划数据抓取时就要设计Plan B。例如分析出租车问题如果抓不到实时的机场出租车调度数据是否可以抓取该城市的航班进出港时刻表公开信息作为替代输入再结合一些合理的假设来构建模型或者是否有相关的学术论文提供了类似场景的仿真数据可供参考在论文中也可以说明“理想情况下应采用XXX数据但由于获取限制本研究采用YYY数据并结合ZZZ假设这在一定程度上是合理的……”。这体现了你解决问题的灵活性。6.5 时间管理数据抓取工作必须在竞赛第一天就取得实质性进展。理想的时间线是第一天上午理解赛题确定所需数据并完成1-2个目标网站的“人肉侦察”和可行性测试。第一天下午到晚上写出核心抓取脚本并成功抓取一小部分样本数据验证数据格式和内容是否符合预期。第二天完善脚本增加错误处理、日志、数据存储开始大规模抓取。同时其他队员可以基于已获取的样本数据开始进行初步的数据分析和模型构思。第三天及之后抓取脚本应进入稳定运行或已完成状态。你的主要精力应转向数据清洗、分析和建模。抓取脚本可能只需要定时运行或处理一些异常。记住抓取数据是为了建模不要本末倒置在抓取环节花费过多时间而压缩了建模和论文写作的时间。一个能跑通、能拿到核心数据的“粗糙”脚本远胜过一个追求完美但迟迟不能交付的“复杂”系统。在数学建模竞赛的三天里完成比完美更重要。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻