news 2026/10/14 15:03:29

LinkedIn员工数据爬虫:从公司名单到线索表的实现思路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LinkedIn员工数据爬虫:从公司名单到线索表的实现思路

简介:LinkedIn员工信息采集爬虫项目,面向需要批量获取指定公司公开员工资料的研究人员、数据分析师与招聘从业者。项目以公司名称为检索入口,通过Python脚本完成搜索、页面解析、详情抓取与数据落盘,并提供应对反爬机制的实现思路,适合有一定Python基础、希望快速理解LinkedIn公开数据采集流程的开发者参考。压缩包共3个文件,包含1个Python主脚本、1个Markdown说明文档及1个Git忽略文件,整体仅5KB,结构简明,便于直接阅读和二次修改。目前已有1601人学习,适合作为轻量级爬虫教学样例或人才挖掘辅助工具。开源代码保留了核心请求与解析逻辑,README中对项目定位、运行方式与合规注意点均有说明;拿到手后可结合自身需求调整抓取字段、存储格式与请求策略,快速搭建面向特定公司的LinkedIn信息采集原型。

1. LinkedinSpider 是什么:输入公司名单,输出一张员工线索表

LinkedinSpider 解决的是一个非常具体的业务问题:你手里有一批目标公司名单,想拿到这些公司里的关键人物——销售找采购决策人,猎头找技术骨干,市场人员找行业里活跃的发言人。手动操作是这样的:打开平台、搜公司名、进入公司主页、翻员工列表、逐个记录职位和城市,两三百家公司就是一到两天的机械劳动,复制粘贴还容易串行。把流程脚本化之后,输入是一个公司名单的文本文件,输出是一张结构化的员工信息表:姓名、当前职位、所在城市、个人主页链接,甚至最近几段工作经历。这篇笔记从“搜公司名”讲到“拿到员工信息并清洗成可用的线索表”,覆盖技术选型、核心代码、参数边界和最容易翻车的地方,适合手里有明确名单但缺少联系人数据的从业者直接照着落地。

2. 选型与原理:为什么“公司名→员工信息”不是简单解析搜索页

2.1 三条技术路线,为什么最后选了“浏览器辅助 + HTTP 接口”

第一反应是直接解析网页 HTML:发请求、拿静态页面、用解析库抽取员工卡。这条路不是不行,而是页面结构频繁调整,平台每次改版你的解析逻辑就要跟着改,维护成本很高。第二反应是纯手工整理,用浏览器内置的搜索、复制功能做,刚才说过,百来家公司还能忍,上千家就没有可行性。第三条路是“浏览器辅助 + HTTP 接口”:先用浏览器模拟登录拿登录态,然后找到网页端实际调用的内部接口,这些接口返回的是结构化 JSON,解析起来比 HTML 稳定得多。

三条路线的对比如下:

方案入口抗改版能力改造成本适用场景
纯 HTML 解析搜索页/员工列表页弱,改版即失效低一次性小批量
浏览器人工复制手动搜索不涉及代码极高几十家以内
浏览器辅助 + 内部接口网页端实际调用的 JSON 接口中上,接口相对稳定中几百到几千家

我一般会优先选第三条。原因是内部接口的返回字段是服务端直接给的,字段名、嵌套结构都比较固定,而且分页、排序、筛选都有明确的参数。你只需要做一次抓包,把接口的域名、路径、请求头和分页参数记下来,后续批量跑的时候用普通请求库。

2.2 关键三样东西:登录态、CSRF Token、分页游标

不管选哪条路,有三样东西是绕不开的。第一是登录态,很多平台的员工列表页在未登录状态下只返回前几条结果,甚至不返回人员数据,所以你要有一个可用的账号会话,把登录后的 Cookie 延续到脚本里。第二是 CSRF Token,平台内部接口为了防跨站请求,几乎所有请求头里都要带一个令牌,这个令牌通常在登录后的首页 HTML 或某个固定接口的响应头里可以拿到。第三是分页游标,员工列表接口很少用“第几页”来分页,而是用一个不透明的游标字符串标记当前位置,请求时带上上一轮返回的游标,才能拿到下一批数据。

这三样东西只要有一个不对,接口的表现就是 401、空列表或者反复返回第一页。后面第 3 章的代码里会逐一说明怎么取、怎么传、怎么判断失效。先记住一点:不要把这三样东西硬编码死在脚本里,它们都有过期时间,要设计成可刷新、可重新导入的配置项。

2.3 能稳定拿到哪些字段,又有哪些字段抓不到

明确字段边界,能避免后期大量返工。我通常把字段分成两类:一类是稳定可用的,一类是可遇不可求的。稳定字段包括:姓名、个人主页链接、当前职位头衔、所在城市或地区、行业关键词、头像、是否在职。这些字段在员工列表接口和个人主页接口里都有,而且格式比较规整。

不稳定或者说经常缺失的字段包括:完整工作经历、教育背景、邮箱、手机号、入离职时间。工作经历和个人主页的可见范围直接挂钩,和登录账号的社交关系、对方的隐私设置有关;邮箱和手机号这类联系方式,平台基本不会直接返回,不要指望脚本能拿到,更别把“抓联系方式”写进预期里。一句话:脚本能做的是把公开页面上已有的信息结构化,不是去挖隐私数据。

注意:平台员工列表页展示的往往不是公司全量员工,而是“与你已有社交关系或相似背景的人”优先排序的结果。这意味着你拿到的是一份优质样本,不一定是完整名册。批量脚本输出的覆盖率和名单质量要以此为基础做评估。

3. 核心脚本搭建:从公司名字到员工信息的三段式实现

3.1 环境准备与登录态导入

环境比较简单,Python 3 加两个常用库就够。需要用到的库有requests、pandas,如果想让流程更自动化,可以加一个浏览器自动化库来帮你在第一次登录时取 Cookie,这不是必须的,因为手动从浏览器开发者工具里复制也能完成同样的目标。

下面是最小环境准备和请求头模板:

# 最小环境 # pip install requests pandas import requests import time import json import random import re import html BASE_URL = "https://www.linkedin.com" HEADERS_TEMPLATE = { "accept": "application/vnd.linkedin.normalized+json+2.1", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", # csrf-token 后续通过 get_token() 动态填充 "csrf-token": "", # cookie 从浏览器登录态的请求头里复制,按 "k1=v1; k2=v2" 格式 "cookie": "", }

这段代码的核心是请求头模板。其中accept字段是平台内部接口要求的响应格式,如果你抓到的请求头里是别的值,以抓包结果为准,不要照抄。cookie是登录态的载体,直接在浏览器开发者工具里找到任意一个接口请求,复制它的 Cookie 请求头即可。

提示:Cookie 有效期通常在几小时到几天不等,脚本要设计成“检测到 401 就停下来提醒重新导出 Cookie”,而不是自动重试,避免账号被风控盯上。

3.2 第一步:公司名搜索,拿到公司实体 ID

公司名不是直接拿去拉员工列表的,平台内部以“实体 ID”为主键,所以第一步要做公司名搜索,拿到匹配的实体 ID 和公司主页信息。搜索接口通常带类型过滤参数,只返回公司类型的候选,避免混入人、职位、群组等噪音。

def get_token() -> str: """从首页 HTML 里提取 csrf-token,首次运行时调用一次即可""" resp = requests.get(BASE_URL + "/feed/", headers=HEADERS_TEMPLATE, timeout=15) # 不同平台的 token 位置不一样,常见做法是从 HTML 中查找 name="csrf-token" m = re.search(r'name="csrf-token" content="([^"]+)"', resp.text) return m.group(1) if m else "" def search_company(keyword: str) -> list[dict]: """输入公司名,返回候选公司实体列表""" url = f"{BASE_URL}/voyager/api/guest/navigation-typeahead" params = { "keywords": keyword, "type": "COMPANY", "q": "typeahead", "start": 0, } resp = requests.get(url, headers=HEADERS_TEMPLATE, params=params, timeout=10) resp.raise_for_status() candidates = [] for item in resp.json().get("elements", []): entity = item.get("entity", {}) urn = entity.get("objectUrn", "") # 形如 urn:li:company:123456 candidates.append({ "id": urn.split(":")[-1], "name": entity.get("name"), "headline": entity.get("headline", ""), # 行业/规模信息一般在这里 "url": entity.get("navigationUrl", ""), }) return candidates

逻辑说明:typeahead是搜索建议接口,输入关键词后返回一组候选实体。代码里取了objectUrn的最后一段作为公司实体 ID,这个 ID 是后续所有接口的主键。headline字段虽然不是公司全称,但通常会带上行业描述,可以用来辅助判断同名公司。如果没有返回结果,优先检查 Cookie 是否过期,而不是改参数。

参数说明:type=COMPANY是类型过滤,不加的话会混入个人用户;start=0表示从第一条开始;keywords会自动做 URL 编码,不需要手动处理。搜索结果通常最多返回 8 个候选,这是平台侧限制,脚本层面尊重就好。

3.3 第二步:拉员工列表,处理分页游标

拿到公司实体 ID 之后,请求员工列表接口。这个接口的分页参数在不同时期不一样,老版本用start/count,新版本用cursor,正确的做法是抓包对比第一页和第二页的请求差异,看看平台到底用了哪个参数。

def fetch_people(company_id: str, cursor: str = "", count: int = 24) -> tuple[list[dict], str]: """拉取公司员工列表,返回 (人员列表, 下一页游标)""" url = f"{BASE_URL}/voyager/api/organization/companies/{company_id}/people" params = { "count": count, "cursor": cursor, # 首页传空字符串,后续传上次返回的 nextCursor "q": "people", "start": 0, # 部分版本用 start/count,以抓包结果为准 } resp = requests.get(url, headers=HEADERS_TEMPLATE, params=params, timeout=15) resp.raise_for_status() payload = resp.json() people = [] for item in payload.get("elements", []): hit = item.get("hitInfo", {}) public_id = hit.get("publicIdentifier", "") people.append({ "public_id": public_id, # 个人主页 URL 后缀 "name": hit.get("name", {}).get("text", ""), "title": hit.get("title", ""), # 当前职位头衔 "location": hit.get("location", ""), # 城市/地区 "profile_url": f"{BASE_URL}/in/{public_id}", }) # 游标位置:新接口通常返回 nextCursor,老接口可能是在 paging 里 next_cursor = payload.get("paging", {}).get("nextCursor", "") return people, next_cursor

逻辑说明:这个函数的关键在cursor参数的传递。第一次调用传空字符串,接口返回第一批数据和下一页的游标;第二次调用时把游标传进去,如此循环直到游标为空。注意这里每次调用返回的不只是数据,还有游标,调用方要用while循环包住整个拉取过程,见 3.5 节的调度逻辑。

参数说明:count=24是平台网页端的分页大小,一次性拉太多会被接口拒绝,保持 24 到 50 之间比较稳妥。publicIdentifier是个人主页 URL 的后缀,比如某个用户主页是/in/john-smith,那么public_id就是john-smith。这个 ID 是后续去重和详情抓取的关键字段。

3.4 第三步:进个人主页抓详情字段

员工列表接口能拿到姓名、职位、城市这些基础字段,但工作经历和教育背景在列表接口里一般没有,需要进个人主页才能拿到。个人主页的抓取有两种路径:一种是把页面源码里内嵌的 JSON 抠出来,另一种是直接调个人资料接口。内嵌 JSON 的方式更通用,因为页面加载时会把首屏数据直接写在 HTML 里。

def fetch_profile(public_id: str) -> dict: """抓取个人详情页,解析内嵌 JSON""" url = f"{BASE_URL}/in/{public_id}" resp = requests.get(url, headers=HEADERS_TEMPLATE, timeout=15) text = resp.text # 常见做法:页面初始数据在 <code id="bootstrap-data-xxx"> 标签里 m = re.search(r'<code id="bootstrap-data-([a-f0-9]+)">(.*?)</code>', text, re.S) if not m: return {"public_id": public_id, "name": "", "experiences": [], "education": []} raw = html.unescape(m.group(2)) data = json.loads(raw) profile = data.get("data", {}).get("profile", {}) experiences = [] for exp in profile.get("experience", []): experiences.append({ "company": exp.get("companyName", ""), "title": exp.get("title", ""), "start": exp.get("timeRange", {}).get("start", {}).get("year", ""), "end": exp.get("timeRange", {}).get("end", {}).get("year", ""), }) return { "public_id": public_id, "name": profile.get("name", ""), "headline": profile.get("headline", ""), "city": profile.get("geoLocationName", ""), "experiences": experiences, "education": [e.get("schoolName", "") for e in profile.get("education", [])], }

逻辑说明:re.search用正则从 HTML 里找到内嵌 JSON 所在的code标签,re.S让.能匹配换行符,避免 JSON 跨行时截断。html.unescape把页面里的\u0026这类转义字符还原成可解析的原文。拿到 JSON 之后,按嵌套结构逐层取字段。这个函数的难点不在请求,而在解析路径,不同页面版本的字段嵌套层级可能不同,写完后要随机抽几个页面验证。

参数说明:public_id直接拼在 URL 里,不需要额外编码,因为这个 ID 本身只包含字母、数字和连字符。timeRange里的start/end字段是工作经历的时间区间,旧版本只有year,新版本可能带month,兼容写法是只取year做展示。教育经历同理,取schoolName即可。

3.5 全流程调度:断点续爬与频率控制

单家公司的流程跑通后,就要考虑批量调度了。批量爬虫最容易犯的错误是两个:一是没有任何进度记录,跑到一半挂了要从头再来;二是请求频率太激进,触发风控。

def run_pipeline(companies_file: str, output_file: str) -> None: """主调度:公司名单 -> 员工列表 -> 个人详情 -> CSV 输出""" companies = [line.strip() for line in open(companies_file, encoding="utf-8") if line.strip()] for idx, company in enumerate(companies, start=1): # 断点续爬:跳过已完成的公司 if idx <= get_last_progress("progress.pos"): continue candidates = search_company(company) selected = select_best_candidate(candidates, company) # 见第 4 章 cursor = "" while True: people, cursor = fetch_people(selected["id"], cursor=cursor) for p in people: profile = fetch_profile(p["public_id"]) save_row(output_file, company, selected, p, profile) if not cursor: break time.sleep(random.uniform(3, 6)) save_progress("progress.pos", idx)

逻辑说明:主循环由两层组成,外层遍历公司,内层翻员工列表。内层循环的退出条件只有一个,就是cursor为空,说明列表页已经翻完。random.uniform(3, 6)是请求间隔,单位是秒,这个间隔不是拍脑袋定的,而是基于接口响应速度和风控阈值综合出来的一个保守值。

参数说明:companies_file是输入文件,每行一个公司名,建议先用 10 家验证再放全量。progress.pos是断点文件,每次跑完一家公司就写一次当前索引,脚本中断后下次启动会跳过去。save_row函数负责把数据追加写入 CSV,为了防止中断丢数据,每拿到一个人就写一行,不要攒到最后统一写。

注意:断点续爬不只是为了省时间,更是为了降低风控风险。一旦脚本因为登录态失效中断,恢复后从断点继续,而不是从头刷一遍,能明显减少短时间内的重复请求。

4. 让数据变得可用:清洗、去重与公司名匹配

4.1 公司名归一化:同一个集团为什么抓到七八个实体

直接拿原始公司名去搜索,返回的候选实体里经常出现“集团母公司”“某事业部”“某地区分公司”等多个实体。比如搜“某某科技集团”,结果里可能有“某某科技集团股份有限公司”“某某科技集团杭州分公司”“某某科技集团创新研究院”,它们确实是同一个集团,但实体 ID 不同,员工列表也完全不同。如果脚本自动选了第一个候选,很可能选到的是分公司,数据范围就不对了。

def normalize_company(name: str) -> str: """公司名归一化:去空格、去后缀,方便比对""" name = name.strip().lower() name = re.sub(r"[\s\-_/]+", " ", name) for suffix in ["inc", "ltd", "llc", "gmbh", "株式会社", "有限公司", "集团", "股份"]: name = name.replace(" " + suffix, " ").replace(suffix + " ", " ") return name.strip()

这个函数的逻辑是把公司名里的空格、连字符统一替换成单个空格,再把常见的公司后缀去掉,得到一个干净的核心词。它解决的问题是同名公司在不同结果里的表述差异,但要注意:归一化只能辅助比对,不能作为最终选型依据。最终还是要看实体 ID、行业描述和公司主页的 URL。

我一般会这么做:先用 30 家公司的名单做一次预跑,把搜索接口返回的所有候选实体存下来,人工确认一遍哪个实体对应原始名单里的公司,然后把“公司名 → 实体 ID”的映射固定到一个本地 JSON 文件里。批量跑的时候优先查映射文件,查不到再走搜索接口。这样既保证了准确性,又避免了每次搜索时选错实体。

4.2 员工去重与职位字段清洗

员工数据抓下来之后,去重是第一步。同一个员工可能既出现在“员工列表”里,又出现在“可能感兴趣的人”推荐里,或者因为一家公司对应多个实体,同一个人被重复抓了两次。去重的关键不是按姓名,而是按public_id,因为姓名可能重名,但个人主页 URL 后缀是唯一的。

def deduplicate(rows: list[dict]) -> list[dict]: """按 public_id 去重,保留第一次出现的记录""" seen = set() result = [] for row in rows: pid = row.get("public_id", "") if pid and pid not in seen: seen.add(pid) result.append(row) return result

逻辑说明:这里用set记录已经见过的public_id,遇到重复直接丢弃。如果你用的是 pandas 处理数据,等价操作是df.drop_duplicates(subset=["public_id"])。注意去重时机放在数据汇总之后、导出 CSV 之前,而且去重要以“同一个人”为准,而不是以“同一个人在同一家公司的记录”为准,因为有的人可能同时出现在两家关联公司的页面上。

职位头衔的清洗同样重要。抓回来的title字段经常有这几类问题:全大写、前后带空白、含有 Emoji、平台本地化语言混杂。我的处理习惯是先去掉 Emoji 和乱码符号,再做首字母大写,最后过滤掉长度小于 2 的无意义短词,比如“未知”“null”“-”。这一步不追求完美,目标是让职位头衔在后续的 Excel 筛选和分类统计里能看、能排序。

4.3 质量校准:随机抽 30 条人工核对

清洗代码写得再花哨,也不如人工抽检一遍。我的习惯是每次跑完一批数据,不管规模多大,都随机抽 30 条出来,核对三个维度:姓名是不是真实人名,公司实体是否对应原始名单里的公司,职位头衔是否可读且合理。核对方法很简单,把抽样结果导出成 CSV,打开后逐条对比原始名单。

import pandas as pd def quality_check(df: pd.DataFrame, sample_size: int = 30) -> pd.DataFrame: """随机抽样并输出,方便人工核对""" sample = df.sample(n=sample_size, random_state=42) return sample[["company_raw", "company_name", "employee_name", "title", "city", "profile_url"]]

这个函数没什么技术难度,但它背后的标准很重要。如果 30 条里出现 2 条以上公司实体不对,说明第 4.1 节的实体映射有问题,要停掉批量任务回头修映射;如果出现 5 条以上title为空或不可读,说明详情页解析路径可能变了,要去抓包对比字段层级。质量抽检不是走流程,是给批量脚本踩刹车的机会。

5. 避坑排查:Linkedin 爬虫最容易翻车的五个地方

5.1 登录态莫名失效,接口开始返回 401

现象:脚本跑得好好的,突然一大批公司返回 401,或者fetch_people里的resp.raise_for_status()直接抛异常。这时候如果继续跑,后面的数据全部是空,浪费请求还容易被风控。

原因:Cookie 过期是最常见的,其次是同一账号在多个设备登录,导致旧的会话被顶下线。还有一个隐蔽原因:csrf-token没有随 Cookie 一起刷新,Cookie 还在有效期内,但 Token 已经失效了,接口也会拒绝请求。

解决:在脚本里加一个统一的异常拦截,遇到 401 就立即停止主循环,输出“登录态失效,请重新导出 Cookie”的提示,不要自动重试。同时把 Cookie 和 Token 的获取封装成独立函数,重新导出后只要更新配置文件就能继续跑。血的教训是:别把 Cookie 写死在代码里,写到外部文件里,不然每次换 Cookie 都要改代码。

5.2 列表翻到第二页就抓不到人

现象:fetch_people第一页返回 24 个人,第二页开始返回空列表,或者返回的数据和第一页完全一样。

原因:分页参数传错了。老接口用start/count分页,第一页start=0,第二页start=24;新接口用cursor,而且start参数可能被忽略。如果你按旧习惯传了start=24而接口实际期待cursor,它只会返回第一页的数据。

解决:抓包对比第一页和第二页的请求 URL,重点看 URL 参数差异。如果差异在cursor字段上,就把start参数从代码里删掉,专注维护游标;如果差异在start上,就反推count是否正确。这个判断决定权在真实接口行为,不在代码习惯。

5.3 明明搜“某公司”,抓回来一堆同名但不对的实体

现象:原始名单里是“某信息技术有限公司”,结果员工列表返回的全是另一个城市的同名公司,或者是一个空壳公司的空列表。

原因:平台搜索候选是按相关性排序的,同名公司在不同地区、不同行业都有,搜索接口返回的第一个候选不一定就是要找的那家。A 同学在这上面踩过坑,脚本自动选了第一个候选,跑完 500 家才发现小半数据是错的,返工成本极高。

解决:预跑阶段把搜索候选全部打印出来,人工确认实体。确认后把映射存成 JSON 文件,批量脚本只读映射,不直接信任搜索接口的排序。映射文件长这样:{"某信息技术有限公司": "123456", "某集团": "789012"}。这一步看似多了一些人工操作,实际上是整个链路里性价比最高的投入。

5.4 抓回来的职位是一堆无意义短词

现象:title字段时不时出现空字符串、“-”“unknown”,或者整个列表里一半人的职位头衔都是“某公司员工”这种泛化描述。

原因:一部分员工设置了隐私,对非好友隐藏职位详情;另一部分是平台在未登录或登录态降级时,会故意返回泛化字段。你要知道,平台对职位头衔的可见性是分级的,与登录账号的关系越远,返回的字段越模糊。

解决:遇到缺失字段不要补默认值,直接在表里留空,后续人工或业务侧补充。批量脚本里做一个统计:如果某家公司的员工列表里title缺失率超过 30%,就把这家公司标记为“待人工处理”,而不是让脏数据混进最终结果里。

5.5 请求频率稍微调快就触发临时限制

现象:间隔从 3 秒调成 1 秒,跑了 200 家之后,接口开始返回 429 或类似的状态码,所有请求都失败。

原因:平台对单个会话的请求频率有阈值,而且这个阈值不是固定的,和账号历史行为、当前时段都有关系。频率看上去像玄学,实际是你在短时间内触发了同一出口地址的请求量上限。

解决:把频率控制做成参数化的,默认间隔 3 到 6 秒随机,遇到 429 就指数退避,比如第一次等 60 秒、第二次等 120 秒、第三次等 300 秒。同时控制并发数,批量任务不要多开,一个进程跑到底,因为并发翻倍并不会让整体速度翻倍,只会让风控概率翻倍。

注意:如果只跑几十家公司的数据,别写脚本,直接手动在平台上搜索导出就可以了。脚本的启动成本、Cookie 维护成本、清洗成本,在小批量场景下远高于手动操作的价值。

6. 进阶用法:如何让爬虫结果真正被业务用上

6.1 输出与增量更新:从一次性脚本变成可持续跑的流程

第一批数据跑完不是终点,业务上通常会每周或每月拉一次新增员工。增量更新的关键是复用上一次的public_id集合:新拉到的数据先做差集,只保留之前没出现过的人,避免新老数据混在一起。这个逻辑用 pandas 写很简单,先读取历史 CSV,再对新数据做public_id的集合差。输出编码上用utf-8-sig,否则 Excel 打开会乱码,这是最容易被忽略的细节。

6.2 上线前的验证节奏与字段覆盖率

我跑批量的固定习惯是三级验证:先拿 10 家公司跑通全流程,确认字段解析正确;再扩到 100 家,观察 429 出现频率和字段缺失率;最后才放全量。字段覆盖率有一个参考线:姓名覆盖率接近 100%,职位覆盖率 90% 左右,城市覆盖率 70% 以上属于正常;如果职位覆盖率低于 80%,优先检查登录态是否降级。每次跑完我都会留一个抽样文件,把每条数据的title和experiences人工扫一眼。这个习惯帮我避免了至少三次大规模返工。

这些年做数据采集,最大的收获是:脚本能解决效率问题,但不能替代业务判断。公司名和实体 ID 的映射要人工确认,字段缺失要允许存在,频率控制要尊重平台限制。把脚本当成一个持续维护的工具,而不是一次性跑完就扔的脚本。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 15:03:17

p5.js 正弦波绘制与动画:The Nature of Code 3.6 Graphing Sine Wave 实战指南

教程文档示例工程 【免费下载链接】website-archive Archive of the Coding Train website (first version) 项目地址&#xff1a; https://gitcode.com/gh_mirrors/we/website-archive 点击查看 免费下载 正弦波是自然界中最基础也最普遍的振荡形态——从钟摆、弹簧到声波、水…

作者头像 李华
网站建设 2026/10/14 15:02:31

插件系统原理与故障排查:从接口约定到插件开发实践

1. 从一次加载失败说起&#xff1a;插件是怎么工作的我先说一个最近的经历。有次在配置一个持续交付流水线&#xff0c;启动服务后给我甩了一个failed to load plugins web boot: 2 entries did not activate的报错&#xff0c;附带两个插件名称。当时第一反应是"插件没生…

作者头像 李华
网站建设 2026/10/14 15:02:26

UE C++组件非构造函数创建全攻略:动态挂载与踩坑指南

做UE C的朋友应该都听过一条“铁律”&#xff1a;组件必须在构造函数里用CreateDefaultSubobject创建。我一开始也是这么背的&#xff0c;直到第一次在运行时给角色动态挂武器、给程序化生成的建筑添门加灯&#xff0c;才意识到这条铁律还有后半句——构造函数只是创建组件最常…

作者头像 李华
网站建设 2026/10/14 15:02:14

智能桌面时钟设计

** 智能桌面时钟设计** 一直想做个智能桌面小摆件&#xff0c;能显示时间&#xff0c;能看天气&#xff0c;能更换背景&#xff0c;现在做好了&#xff0c;贴出来分享一下&#xff0c;记录一下历程。 最先想到的是屏幕必须是圆的&#xff0c;平板和手机已经把方…

作者头像 李华
网站建设 2026/10/14 15:01:44

Neo4j+RAG+Agent工程落地实战:多模态知识库与抗投毒架构

1. 项目概述&#xff1a;这不是一份“新闻简报”&#xff0c;而是一份面向工程落地的Agent/LLM技术实践切片“Agent / LLM 技术精选日报 2026-09-28&#xff08;知乎版&#xff09;”这个标题&#xff0c;乍看像一份资讯汇编&#xff0c;但实际它承载的是当前AI工程化最前沿、…

作者头像 李华
网站建设 2026/10/14 15:01:27

数学规划模型实战指南:从线性规划到生产排产优化

我做运筹优化相关工作这些年&#xff0c;被问得最多的一句话是&#xff1a;你们天天说数学规划模型&#xff0c;是不是就是列几个方程扔给电脑算&#xff1f;每次我都得解释——列方程只是最后一步&#xff0c;真正难的&#xff0c;是把一个具体的业务问题翻译成人话&#xff0…

作者头像 李华