Python爬虫实战:从OP.GG抓取英雄联盟战绩数据并分析
1. 项目缘起与核心价值最近在社区里看到不少朋友在讨论游戏数据尤其是《英雄联盟》的战绩分析。作为一个老玩家兼技术爱好者我经常在想如果能把自己或者关注的高手的对局数据系统地爬取下来做点个性化的分析比如看看自己哪个时间段胜率高、用哪个英雄打特定位置更顺手那该多有意思。市面上虽然有一些现成的助手App但数据要么不全要么就是展示方式固定很难满足深度定制的需求。比如你想分析自己近100场排位赛中前15分钟补刀数与最终胜利的相关性或者想批量查看某个英雄在不同版本下的胜率变化这些需求通用工具很难满足。这就是“爬虫”技术大显身手的地方了。通过编写爬虫程序我们可以直接从游戏官方的数据接口或相关数据网站自动化地获取原始、详细的战绩数据然后存入自己的数据库接下来想怎么分析、怎么可视化就完全由自己掌控了。这不仅仅是获取数据更是一个理解网络请求、处理反爬机制、清洗和结构化数据的完整实战过程。对于想学习Python爬虫或者对数据分析感兴趣的朋友来说这是一个绝佳的练手项目。它涵盖了从网络请求、数据解析到数据存储的全流程而且结果直观有趣动力十足。2. 整体技术方案与核心思路拆解2.1 目标数据源分析与选择爬取英雄联盟数据第一步也是最重要的一步就是确定数据从哪里来。我们不能直接去“攻击”游戏服务器而是寻找官方或第三方提供的数据接口。目前主流的数据源有几个方向官方开发者API如 Riot API这是最权威、最稳定的数据来源。拳头公司为开发者提供了完善的API可以获取到极其详细的比赛数据包括每个玩家的装备购买时间、技能加点顺序、每分钟金钱经验等。但使用它需要注册开发者账号申请API Key并且有严格的调用频率限制。对于个人学习和非商业用途免费 tier 的额度基本够用但需要一定的申请流程。第三方数据聚合网站如 OP.GG、U.GG、LeagueOfGraphs 等。这些网站本身的数据就是通过API或其它方式聚合而来并做了很好的可视化。爬取这些网站相当于“爬取爬虫的结果”。优点是无需API Key直接可见缺点是网站会有反爬措施如验证码、请求频率限制、动态加载且数据结构是为前端展示设计的需要自己解析HTML稳定性不如官方API。游戏客户端本地日志极不推荐。这涉及对客户端文件的深度解析复杂度高且可能违反用户协议。我们的方案选择为了项目的完整性和学习价值我们将采取一种“混合策略”进行讲解。核心以模拟浏览器访问第三方网站如 OP.GG为主线因为这种方式更贴近大多数爬虫初学者的实战场景面对的是有反爬的网页。同时我们会对比介绍官方API的申请与调用方式让你了解更规范的途径。本教程将重点放在前者因为它涉及的反爬技巧、数据解析更具通用性。2.2 技术栈与工具选型工欲善其事必先利其器。以下是完成这个项目需要的主要工具库及其作用Python 3.7: 我们的主力编程语言社区活跃库丰富。Requests: 用于发送HTTP请求获取网页源代码。简单易用是爬虫的基石。BeautifulSoup4 (bs4): 当数据直接存在于网页HTML中时用它来解析和提取数据。它像一把手术刀可以精准地找到HTML标签里的内容。Selenium: 当目标网站的数据是通过JavaScript动态加载即右键“查看网页源代码”看不到数据时就需要它。它可以控制一个真实的浏览器如Chrome去访问页面等待JS执行完毕后再获取完整的页面内容。这是应对现代前端框架如React, Vue的利器。Pandas: 数据清洗、处理和分析的瑞士军刀。爬下来的原始数据往往是杂乱无章的列表或字典用Pandas可以方便地转换成结构清晰的表格DataFrame进行过滤、排序、统计等操作。SQLite / MySQL / PostgreSQL: 用于持久化存储数据。SQLite轻量适合本地单机项目MySQL/PostgreSQL功能更强大适合数据量较大或需要远程访问的场景。我们将使用SQLite作为示例。Fiddler / Charles / 浏览器开发者工具: 这些不是Python库而是至关重要的辅助工具。用于“抓包”即监听浏览器和服务器之间的网络请求帮助我们找到真正传输数据的那个请求API接口以及分析请求头、参数、Cookie等关键信息。注意选择Selenium意味着你需要下载对应的浏览器驱动如ChromeDriver并匹配你的浏览器版本。这比纯RequestsBS4的方案稍重但为了应对更普遍的情况我们以Selenium为主进行讲解。如果目标网站没有JS加载可以降级使用RequestsBS4效率更高。2.3 核心爬取流程设计整个爬虫的运作流程可以概括为以下几步这是一个通用的爬虫思维框架目标确定明确要爬取哪个大区如艾欧尼亚、哪个玩家的数据。请求模拟使用Selenium打开目标玩家的战绩页面如https://www.op.gg/summoners/region/summonerName。页面等待与渲染确保页面上的比赛列表、KDA等数据已经完全加载出来。这里需要设置合理的等待时间或等待特定元素出现。元素定位与数据解析使用Selenium或结合BeautifulSoup来定位到包含战绩的HTML元素并从中提取出文本信息如英雄名称、K/D/A、胜负、比赛时长等。数据存储将提取出的结构化数据通常是一个字典或列表保存到文件CSV, JSON或数据库中。翻页与循环如果有多页战绩模拟点击“下一页”按钮或分析翻页的URL规律循环执行步骤2-5。反爬应对在过程中加入随机延迟、使用代理IP池如果需要大量爬取、处理可能的验证码等。3. 实战环境搭建与核心代码解析3.1 环境准备与依赖安装首先确保你的电脑上安装了Python。打开命令行CMD或Terminal创建一个新的项目目录并安装必要的库。# 创建项目目录并进入 mkdir lol-match-spider cd lol-match-spider # 创建虚拟环境推荐避免包冲突 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 安装核心库 pip install requests beautifulsoup4 selenium pandas # 安装用于连接SQLite的库Python标准库自带sqlite3一般无需安装 # 如果需要其他数据库如pymysql for MySQL # pip install pymysql接下来你需要下载与你的Chrome浏览器版本匹配的ChromeDriver。访问 ChromeDriver官网 或使用国内镜像站下载将下载的chromedriver.exe(Windows) 或chromedriver(macOS/Linux) 文件放在项目目录下或者将其所在路径添加到系统的环境变量中。3.2 爬虫核心代码实现我们计划爬取OP.GG上某个玩家的近期战绩列表。以下是一个分步实现的示例代码框架包含了关键步骤和注释。import time import pandas as pd 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 from selenium.common.exceptions import TimeoutException, NoSuchElementException class LOLMatchSpider: def __init__(self, summoner_name, regionkr): 初始化爬虫 :param summoner_name: 召唤师名称 :param region: 服务器地区op.gg上kr代表韩服www代表美服等 self.summoner_name summoner_name self.region region # 构建目标URL注意op.gg的URL格式 self.base_url fhttps://www.op.gg/summoners/{region}/{summoner_name} # 初始化Selenium WebDriver这里以Chrome为例 options webdriver.ChromeOptions() # 添加一些选项以更好地模拟真人浏览器并可能规避一些检测 options.add_argument(--disable-blink-featuresAutomationControlled) options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) # 无头模式不显示浏览器界面调试时可注释掉 # options.add_argument(--headless) self.driver webdriver.Chrome(optionsoptions) # 隐藏WebDriver特征 self.driver.execute_script(Object.defineProperty(navigator, webdriver, {get: () undefined})) self.wait WebDriverWait(self.driver, 10) # 显式等待最多等10秒 # 用于存储所有比赛数据的列表 self.all_matches [] def fetch_match_list(self): 访问玩家主页并获取战绩列表 print(f正在访问 {self.base_url} ...) self.driver.get(self.base_url) # 关键等待战绩列表区域加载完成。通过CSS选择器定位。 # OP.GG的战绩列表通常在一个class包含game-list的div里 try: match_list_container self.wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, div[class*game-list])) ) print(战绩列表加载成功。) except TimeoutException: print(页面加载超时可能元素选择器已更新或网络问题。) self.driver.save_screenshot(timeout.png) # 保存截图便于调试 return False # 等待片刻确保动态内容如KDA加载完全 time.sleep(2) # 开始解析当前页的战绩 self._parse_current_page_matches() return True def _parse_current_page_matches(self): 解析当前页面显示的所有战绩卡片 # 找到所有单场战绩的卡片元素。OP.GG的每场战绩通常在一个div里class名可能类似result-WIN或result-LOSE # 这个选择器需要根据实际网页结构调整这里是一个示例 match_cards self.driver.find_elements(By.CSS_SELECTOR, div[class*result-]) print(f本页找到 {len(match_cards)} 场对局。) for card in match_cards: match_data {} try: # 1. 解析胜负 (WIN/LOSE) # 胜负信息通常直接体现在容器的class名中或者内部有一个特定元素 class_name card.get_attribute(class) if WIN in class_name: match_data[result] 胜利 elif LOSE in class_name: match_data[result] 失败 else: match_data[result] 未知 # 2. 解析游戏模式如单双排、灵活组排、匹配 # 查找包含游戏模式文本的元素 game_type_elem card.find_element(By.CSS_SELECTOR, .game-type) # 示例选择器 match_data[game_type] game_type_elem.text.strip() if game_type_elem else N/A # 3. 解析英雄名称 champion_elem card.find_element(By.CSS_SELECTOR, .champion-name) # 示例选择器 match_data[champion] champion_elem.text.strip() if champion_elem else N/A # 4. 解析K/D/A kda_elem card.find_element(By.CSS_SELECTOR, .kda) # 示例选择器 kda_text kda_elem.text.strip() if kda_elem else N/A # 假设格式为 12 / 5 / 8 match_data[kda] kda_text # 5. 解析比赛时长 time_elem card.find_element(By.CSS_SELECTOR, .time) # 示例选择器 match_data[duration] time_elem.text.strip() if time_elem else N/A # 6. 解析比赛日期 date_elem card.find_element(By.CSS_SELECTOR, .date) # 示例选择器 match_data[date] date_elem.text.strip() if date_elem else N/A # 将本场数据添加到总列表 self.all_matches.append(match_data) print(f已解析: {match_data[date]} | {match_data[result]} | {match_data[champion]} | {match_data[kda]}) except NoSuchElementException as e: # 如果某个元素找不到跳过这场对局记录日志 print(f解析单场对局时遇到元素缺失跳过。错误: {e}) continue def run(self): 运行爬虫的主流程 if self.fetch_match_list(): print(f共爬取到 {len(self.all_matches)} 场对局数据。) # 将数据转换为Pandas DataFrame方便查看和后续处理 df pd.DataFrame(self.all_matches) print(df.head()) # 打印前几行看看 # 保存到CSV文件 df.to_csv(f{self.summoner_name}_matches.csv, indexFalse, encodingutf-8-sig) print(f数据已保存至 {self.summoner_name}_matches.csv) else: print(爬取过程失败。) # 关闭浏览器 self.driver.quit() # 使用示例 if __name__ __main__: # 替换成你想爬取的召唤师名字和区服 spider LOLMatchSpider(summoner_nameHide on bush, regionkr) spider.run()代码关键点解析初始化与反爬在__init__中我们通过ChromeOptions添加了一些参数来隐藏自动化特征这是绕过一些简单反爬检测的常用手段。execute_script那行代码直接修改了浏览器的navigator.webdriver属性使其看起来更像普通浏览器。显式等待 (WebDriverWait)fetch_match_list方法中的WebDriverWait是Selenium最佳实践之一。它不会盲目地time.sleep一个固定时间而是等待页面特定元素出现这样既高效又稳定。这里我们等待一个包含game-list的div元素出现。数据解析 (_parse_current_page_matches)这是最核心也最脆弱的部分。我们通过find_element和CSS选择器来定位元素。请注意.game-type,.champion-name等选择器是我根据常见结构假设的示例实际OP.GG的网页结构可能不同需要你用浏览器开发者工具实时查看并调整。错误处理在解析每张卡片时使用了try...except捕获NoSuchElementException。网页结构可能微调某场比赛可能缺少某些元素比如极地大乱斗没有补刀数良好的错误处理能保证程序不会因为一场比赛解析失败而崩溃。数据存储最后用Pandas将列表转换成DataFrame并保存为CSV文件。CSV格式通用方便用Excel打开或导入数据库。3.3 动态数据与API接口抓取上面我们爬取的是直接渲染在HTML里的数据。但更多详细数据如具体的装备列表、伤害图表、时间线数据往往是页面加载后通过JavaScript调用后台API接口异步获取的。这时直接解析HTML就抓不到了。解决方案抓包分析API。打开Chrome开发者工具F12切换到Network网络标签页。刷新OP.GG的战绩页面或者点击“加载更多比赛”。在Network面板里你会看到很多请求。筛选XHR/Fetch类型的请求这些通常是数据传输的API。仔细查看这些请求的URL、请求方法GET/POST、请求头特别是Authorization,Cookie,X-Riot-Token等和响应内容Preview或Response标签。找到那个返回JSON格式比赛数据的请求。它的响应体可能是一个包含比赛ID列表的JSON或者是详细的比赛数据JSON。模拟这个请求一旦找到真正的数据接口我们的爬虫就可以从“模拟浏览器”升级为更高效的“直接请求API”。我们可以用requests库带上必要的请求头尤其是Cookie它代表了你的登录状态或会话直接向这个API地址发送请求拿到结构化的JSON数据这比解析HTML要稳定和高效得多。import requests import json # 假设通过抓包找到了获取比赛详情的API match_api_url https://op.gg/api/v1.0/internal/bypass/summoners/region/summonerName/matches # 示例URL非真实 # 关键构造请求头通常需要Cookie和User-Agent headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., Accept: application/json, # Cookie: 你的Cookie字符串从浏览器开发者工具里复制, # 重要 # Authorization: Bearer ..., # 如果有的话 Referer: fhttps://www.op.gg/summoners/region/summonerName # 有时需要 } # 可能还需要查询参数 params { queue: 420, # 排位赛 limit: 20, hl: zh_CN } response requests.get(match_api_url, headersheaders, paramsparams) if response.status_code 200: match_data response.json() # 直接得到Python字典/列表 # 处理 match_data... print(json.dumps(match_data, indent2, ensure_asciiFalse)) else: print(f请求失败状态码{response.status_code})重要提醒直接调用第三方网站的API可能违反其服务条款且接口地址和参数可能随时变更。此方法仅用于学习网络请求原理。对于持续、大量的数据需求强烈建议使用官方Riot API它稳定、合法且有完善的文档。4. 数据清洗、存储与简单分析4.1 使用Pandas进行数据清洗爬取下来的原始数据往往存在缺失值、格式不一致等问题。Pandas可以轻松处理这些。import pandas as pd # 读取刚才保存的CSV df pd.read_csv(Hide on bush_matches.csv) # 1. 查看数据概览和信息 print(df.info()) # 查看列名、非空数量、数据类型 print(df.head()) # 2. 处理KDA列拆分成Kill, Death, Assist三列 # 假设kda列格式为 12 / 5 / 8 def split_kda(kda_str): try: k, d, a map(int, kda_str.split(/)) return pd.Series([k, d, a]) except: return pd.Series([0, 0, 0]) # 对于异常数据返回0 df[[Kills, Deaths, Assists]] df[kda].apply(split_kda) # 3. 计算KDA比率(KA)/D防止除零 df[KDA_Ratio] df.apply(lambda row: (row[Kills] row[Assists]) / max(row[Deaths], 1), axis1) # 4. 将比赛时长从字符串如32:15转换为分钟数浮点数 def convert_duration(dur_str): if : in dur_str: parts dur_str.split(:) if len(parts) 2: return int(parts[0]) int(parts[1])/60 return 0 df[duration_minutes] df[duration].apply(convert_duration) # 5. 处理日期列转换为datetime类型如果原始是1天前需要更复杂的处理这里假设是具体日期 # df[date] pd.to_datetime(df[date], errorscoerce) # 如果日期格式规整 # 6. 删除不必要的列或处理缺失值 # df df.dropna(subset[champion]) # 删除英雄名为空的行 # df[game_type].fillna(未知, inplaceTrue) # 填充空值 print(df[[result, champion, Kills, Deaths, Assists, KDA_Ratio, duration_minutes]].head())4.2 数据存储到数据库将清洗后的数据存入SQLite数据库便于长期管理和复杂查询。import sqlite3 # 连接数据库如果不存在则创建 conn sqlite3.connect(lol_matches.db) cursor conn.cursor() # 创建表 create_table_sql CREATE TABLE IF NOT EXISTS match_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, summoner_name TEXT, region TEXT, game_date TEXT, game_type TEXT, champion TEXT, result TEXT, kills INTEGER, deaths INTEGER, assists INTEGER, kda_ratio REAL, duration_min REAL, raw_data TEXT ); cursor.execute(create_table_sql) # 假设我们有一个清洗后的DataFrame df_clean # 将DataFrame的数据插入数据库 for index, row in df.iterrows(): insert_sql INSERT INTO match_history (summoner_name, region, game_date, game_type, champion, result, kills, deaths, assists, kda_ratio, duration_min) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) cursor.execute(insert_sql, ( Hide on bush, # 召唤师名 kr, # 区服 row.get(date, N/A), row.get(game_type, N/A), row.get(champion, N/A), row.get(result, N/A), row[Kills], row[Deaths], row[Assists], row[KDA_Ratio], row[duration_minutes] )) conn.commit() print(数据已存入数据库。) # 查询示例计算某个英雄的平均KDA query_sql SELECT champion, COUNT(*) as games, AVG(kills) as avg_kills, AVG(deaths) as avg_deaths, AVG(assists) as avg_assists, AVG(kda_ratio) as avg_kda_ratio, SUM(CASE WHEN result 胜利 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) as win_rate FROM match_history WHERE summoner_name Hide on bush GROUP BY champion ORDER BY games DESC; df_stats pd.read_sql_query(query_sql, conn) print(df_stats.head()) conn.close()4.3 简单的数据分析与可视化有了干净的数据我们就可以进行一些有趣的分析了。这里用Pandas和Matplotlib做一个简单的示例。import matplotlib.pyplot as plt # 设置中文字体如果需要显示中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 # 1. 英雄使用频率排行榜 champion_counts df[champion].value_counts().head(10) plt.figure(figsize(10,6)) champion_counts.plot(kindbarh) plt.title(最常使用的英雄 Top 10) plt.xlabel(出场次数) plt.tight_layout() plt.show() # 2. 不同游戏模式的胜率 if game_type in df.columns: win_rate_by_mode df.groupby(game_type)[result].apply(lambda x: (x 胜利).sum() / len(x) * 100) print(各模式胜率) print(win_rate_by_mode) # 3. KDA分布直方图 plt.figure(figsize(10,6)) plt.hist(df[KDA_Ratio], bins20, edgecolorblack, alpha0.7) plt.axvline(df[KDA_Ratio].mean(), colorred, linestyle--, labelf平均KDA: {df[KDA_Ratio].mean():.2f}) plt.xlabel(KDA比率) plt.ylabel(场次) plt.title(KDA比率分布) plt.legend() plt.tight_layout() plt.show()5. 常见问题、反爬策略与优化建议5.1 高频问题与解决方案元素定位失败报错NoSuchElementException原因网页结构发生变化或者页面未完全加载。解决更新选择器使用浏览器开发者工具的“检查”功能重新确认目标元素的CSS选择器或XPath。优先使用相对稳定、语义化的属性如>

相关新闻

Android Studio 2024.3.1 安装与 AI 编程助手集成全攻略

Android Studio 2024.3.1 安装与 AI 编程助手集成全攻略

在实际 Android 开发中,从零开始配置一个高效、智能的开发环境,往往比写第一行代码更耗费精力。很多开发者卡在环境安装、依赖配置、工具集成这些前期步骤上,尤其是面对 Android Studio 这类大型 IDE 以及层出不穷的 AI 辅助编程工具时&#…

2026/8/25 7:39:26 阅读更多 →
利用OpenRouter与Inkling免费资源,从零构建AI智能体测试环境

利用OpenRouter与Inkling免费资源,从零构建AI智能体测试环境

在实际 AI 应用开发中,我们经常面临一个核心矛盾:一方面,我们需要快速测试和验证不同大语言模型(LLM)的能力,以找到最适合特定任务的模型;另一方面,直接对接各大模型厂商的 API 不仅…

2026/8/25 7:39:26 阅读更多 →
数据中心基础设施运维体系:从风险管控到智能运维的实战指南

数据中心基础设施运维体系:从风险管控到智能运维的实战指南

1. 项目概述:从“救火队”到“体系化”的运维跃迁干了十几年数据中心运维,从当年拎着螺丝刀在机房里“跑断腿”,到现在坐在监控大屏前“运筹帷幄”,我最大的感触就是:运维的本质不是修设备,而是管风险。今天…

2026/8/25 7:38:26 阅读更多 →

最新新闻

TLS协议深度解析:从握手流程到安全配置与排错实践

TLS协议深度解析:从握手流程到安全配置与排错实践

1. 从HTTP到HTTPS:为什么我们需要TLS?如果你在浏览器里输入一个网址,前面是http://,那么你和网站服务器之间的所有对话,就像在拥挤的咖啡馆里大声聊天,任何人都能听到。你输入的密码、看的私密信息、甚至银…

2026/8/25 8:09:35 阅读更多 →
TLS协议深度解析:从HTTP到HTTPS的安全基石与实战配置

TLS协议深度解析:从HTTP到HTTPS的安全基石与实战配置

1. 从HTTP到HTTPS:为什么我们需要TLS? 如果你在浏览器里输入一个网址,前面是 http:// ,那么你和服务器之间所有的对话,比如你输入的账号密码、看的文章内容,都是在“裸奔”。任何一个处在你们网络路径上…

2026/8/25 8:09:35 阅读更多 →
招聘会 SaaS 系统后台操作大公开!让招聘会组织工作事半功倍

招聘会 SaaS 系统后台操作大公开!让招聘会组织工作事半功倍

摘要:本文详细介绍云招聘网络招聘会系统的后台操作指南,涵盖系统登录、招聘会信息配置、招聘会流程管理、数据统计与分析以及系统维护与管理五大核心功能模块,帮助读者快速掌握从创建招聘会、审核企业入驻、管理职位发布到分析招聘效果的全流…

2026/8/25 8:09:35 阅读更多 →
Unity C# 调试原理大揭秘

Unity C# 调试原理大揭秘

一、先建立整体认知:调试到底在调什么? 当你在 IDE(VS/Rider)里点了个断点,程序停下来,能看变量、能单步走——这背后其实是三方在通信: 你的 IDE(调试器前端) ←→ 调试协议 ←→ Unity运行时(被调试进程)Debugger Protocol Ru…

2026/8/25 8:09:35 阅读更多 →
射击游戏后台开发:物理引擎应用与移动模拟实战

射击游戏后台开发:物理引擎应用与移动模拟实战

写在前面:本文以《无限法则》这类"吃鸡"射击游戏为背景,聊聊后台是怎么处理物理和移动的。这里讲的是行业通用的技术思路和原理,而非某款游戏的内部实现细节,重在把"门道"讲明白。 开篇:一个让你血压飙升的场景 你在玩射击游戏,明明准星死死套住敌人…

2026/8/25 8:09:35 阅读更多 →
近场DOA估计:降维MUSIC算法原理、实现与工程优化

近场DOA估计:降维MUSIC算法原理、实现与工程优化

1. 项目概述与核心价值上次我们聊了近场DOA估计的基本模型和传统MUSIC方法面临的“维度灾难”问题。很多朋友反馈说,原理懂了,但一看到那庞大的谱峰搜索计算量就头疼,感觉离实际应用还很远。这感觉我太懂了,当年我第一次把理论公式…

2026/8/25 8:08:35 阅读更多 →

日新闻

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

【题目来源】 https://www.luogu.com.cn/problem/P7912 【题目描述】 小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里&#x…

2026/8/25 0:00:34 阅读更多 →
Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG 【免费下载链接】transformers.js State-of-the-art Machine Learning for the web. Run 🤗 Transformers directly in your browser, with no need for a server! 项目地址: https:/…

2026/8/25 0:00:34 阅读更多 →
数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

1. 项目概述:从“会做”到“会写”的竞赛核心跃迁“全国大学生数学建模竞赛”,这个名字对理工科学生来说,分量极重。每年,无数团队在三天三夜的时间里,为一个开放性问题绞尽脑汁,从建立模型、求解算法到编程…

2026/8/25 0:00:34 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 3:38:12 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 3:38:23 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/24 20:22:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/23 12:10:44 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/24 11:20:22 阅读更多 →