快速开始 · 无需登录 · CLI · 端点 · 数据 · 错误 · MCP 和 Claude Code · 免费额度 · 文档 · 支持
使用 Python 以 JSON 格式获取 LinkedIn 个人资料、公司、职位和帖子。无需登录 LinkedIn,也无需浏览器。基于 Bright Data LinkedIn 爬虫工具 API 构建。
使用 Bright Data Python SDK。完整 API 文档:LinkedIn 爬虫工具 API。
这里还提供:用于个人资料的单命令 CLI,以及完全不需要 Python 的 Bright Data CLI。
LinkedIn 个人资料数据属于个人数据。请在适用于你的法律范围内使用:Bright Data 合规说明。
需要 Python 3.10 或更高版本。
pip install brightdata-sdk
export BRIGHTDATA_API_TOKEN=YOUR_API_KEY从 Bright Data 控制面板获取令牌。项目根目录中的 .env 文件也可以使用,但虚拟环境必须位于项目内。
也可以跳过令牌。运行一次 npx -p @brightdata/cli bdata login:它会打开浏览器,此后 SDK 会自行找到已存储的凭据,供你以及在该终端中工作的任何编码智能体使用。智能体无法点击完成登录,因此请先自行操作。
还没有账户?创建账户;新账户每月可获得 5,000 个免费额度。
from brightdata import SyncBrightDataClient
with SyncBrightDataClient(auto_create_zones=False) as client:
profile = client.scrape.linkedin.profiles("https://www.linkedin.com/in/satyanadella/").data
print(profile["name"], "|", profile["position"])
print(profile["followers"], "followers,", profile["connections"], "connections")Satya Nadella | Chairman and CEO at Microsoft
12173313 followers, 500 connections
通常不到一分钟:API 运行一个作业,SDK 等待其完成。每份个人资料消耗一个额度。
每次都要传递 auto_create_zones=False。如果保持开启,SDK 会在启动时为网络解锁器和 SERP 创建区域,这是此爬虫从不使用的另外两款 Bright Data 产品;在没有付款方式的账户上,区域创建会失败(sdk-python#57)。
LinkedIn 爬虫工具 API 不需要 LinkedIn 账户,也不需要登录 LinkedIn。唯一的凭据是 Bright Data API 密钥,可将其设置为 BRIGHTDATA_API_TOKEN,或通过 bdata login 存储。
此仓库中的命令会同时对多个个人资料运行 Python 快速入门,并写入一个 JSON 文件。
pip install git+https://github.com/bright-cn/linkedin-scraper-python
linkedin-scraper satyanadella reidhoffmanFetching 2 LinkedIn profiles: satyanadella, reidhoffman
One job for all of them, usually one to three minutes. One credit per profile.
asking 2 profiles...
got satyanadella: 34 fields (Satya Nadella)
got reidhoffman: 38 fields (Reid Hoffman)
Saved 2 of 2 profiles as JSON to linkedin.json
它既可以接受个人资料 URL,也可以直接接受其中的 slug。
在终端中,asking 行会被以下内容原地替换,让你可以看到它正在运行以及已经运行了多长时间:
⠹ 2 profiles 0:00:41
--out PATH output file, default linkedin.json
python -m linkedin_scraper 也可以使用。
你请求的所有个人资料都会进入同一个作业。API 按记录而不是按作业计费,而且处理一个 URL 与处理十个 URL 所需的作业时间大致相同。
也可以导入它而不是直接运行,以便为每份个人资料获取 ok 和 error,而不是原始结果行。scrape 不会因为某一份个人资料无效而抛出异常;请先检查 ok,再读取 profile:
from linkedin_scraper import scrape
for outcome in scrape(["satyanadella", "zz-not-a-real-profile-zz"]):
if outcome.ok:
print(f"{outcome.slug}: {outcome.profile['name']}")
else:
print(f"{outcome.slug} failed: {outcome.error}")satyanadella: Satya Nadella
zz-not-a-real-profile-zz failed: The profile is hidden or private.
该命令涵盖下表第一行。SDK 的其余 LinkedIn 功能列在其他行中,并记录于 LinkedIn 爬虫工具 API 文档。以下每个代码片段都是完整的,只需要 brightdata-sdk:可直接按原样粘贴。它们都会在每周一通过 Actions 运行,规模较小的检查则每隔一天运行一次,顶部徽章显示最新结果。
| 你已有 | 你想要 | 调用 |
|---|---|---|
| 个人资料 URL | 该个人资料 | client.scrape.linkedin.profiles(url) |
| 名字和姓氏 | 匹配的个人资料 | client.search.linkedin.profiles(first_name, last_name),请参阅下方说明 |
| 公司 URL | 该公司 | client.scrape.linkedin.companies(url) |
| 职位 URL | 该职位信息 | client.scrape.linkedin.jobs(url) |
| 关键词或地点 | 匹配的职位信息 | client.search.linkedin.jobs(keyword=..., location=...),请参阅下方说明 |
| 帖子 URL | 该帖子 | client.scrape.linkedin.posts(url) |
| 个人资料或公司 URL | 其帖子 | client.search.linkedin.posts(url, start_date=..., end_date=...) |
search.linkedin.profiles 接受名字和姓氏,而不是 URL。它是按姓名进行的人员搜索。此 README 仅说明该功能存在,不会针对真实个人进行演示。
search.linkedin.jobs 没有限制返回职位数量的参数,并且每条职位信息会收取一个额度。宽泛的关键词可能匹配数千条结果。这里不会运行它,因为此 README 中的每个代码片段都会每周重新运行。在大范围运行前,请使用 company、location 和 timeRange 缩小范围。
这里没有基于固定职位 URL 的示例。职位可能关闭,而固定到该职位的代码片段会在其关闭当周变红。
这些调用全都是异步作业。SDK 会触发作业、进行轮询,并在准备就绪后返回。API 的同步端点仅支持原始 HTTP,最多 20 个 URL,时间限制为一分钟。
之所以会出现类似上述已失效个人资料的错误行,是因为 SDK 通过 include_errors=true 请求返回这些行。API 默认关闭此选项。
使用一个 URL 调用 scrape 时,会以字典形式返回一条记录;使用多个 URL 时,则返回列表。timeout 参数的单位是秒,默认为 180。
一组 URL 属于一个作业,而不是每份个人资料各自一个作业。
from brightdata import SyncBrightDataClient
with SyncBrightDataClient(auto_create_zones=False) as client:
results = client.scrape.linkedin.profiles([
"https://www.linkedin.com/in/satyanadella/",
"https://www.linkedin.com/in/reidhoffman/",
])
for result in results:
row = result.data
source = row.get("input_url") or row["input"]["url"] # an error row has only input
print(source, "|", row.get("name") or row["error"])https://www.linkedin.com/in/reidhoffman/ | Reid Hoffman
https://www.linkedin.com/in/satyanadella/ | Satya Nadella
URL 的输入顺序是先 satyanadella、后 reidhoffman,但结果行的返回顺序正好相反。每一行仍然正确,因为它读取的是结果行自身的 input_url。
应像上面一样,通过结果行自身的 input_url 判断它属于哪份个人资料,绝不要使用 result.url。SDK 会按位置将结果与你传入的 URL 配对,但 API 每次运行都可能以不同顺序返回结果行,因此 result.url 可能显示某个人的姓名,而 result.data 中却包含另一个人的个人资料。每条结果也都会标记为 success=True,包括已失效个人资料的错误行(sdk-python#60)。错误行没有 input_url;其个人资料通过 input["url"] 标识。
如果处理的个人资料不止几份,请勿让进程阻塞一小时。触发作业、保留快照 ID,并在准备就绪后获取。快照可下载 30 天。
import time
from brightdata import SyncBrightDataClient
with SyncBrightDataClient(auto_create_zones=False) as client:
job = client.scrape.linkedin.profiles_trigger("https://www.linkedin.com/in/satyanadella/")
print("snapshot:", job.snapshot_id)
while (status := client.scrape.linkedin.profiles_status(job.snapshot_id)) not in ("ready", "failed"):
time.sleep(5)
print("status:", status)
record = client.scrape.linkedin.profiles_fetch(job.snapshot_id)[0]
print("fetched:", record["name"], "|", record["current_company_name"])snapshot: sd_mu717o9x2md4afafsv
status: ready
fetched: Satya Nadella | Microsoft
from brightdata import SyncBrightDataClient
with SyncBrightDataClient(auto_create_zones=False) as client:
company = client.scrape.linkedin.companies("https://www.linkedin.com/company/bright-data/").data
print(company["name"], "|", company["employees_in_linkedin"], "employees on LinkedIn")Bright Data | 407 employees on LinkedIn
个人资料中最常用的字段:
name position city current_company_name followers connections experience
代码没有硬编码任何字段列表。API 返回的所有内容都会进入 result.data,也会写入命令生成的文件。
API 在数据结构中使用 pii: true 将其中 8 个字段标记为个人数据:id、name、about、url、input_url、linkedin_id、first_name 和 last_name。
get_metadata() 会丢弃该标记。它会为每个字段保留 type、active、required 和 description,并丢弃其余内容(sdk-python#61)。要读取该标记,请使用同一令牌自行请求 https://api.brightdata.com/datasets/gd_l1viktl72bvl7bjuj0/metadata。下表正是这样做的。
全部 47 个字段,含类型和描述
每天通过原始元数据端点从数据集结构重新生成,因此不会过时。个人资料会包含适用于它的字段:示例文件包含这 47 个字段中的 32 个,另外还有数据结构中未列出的 timestamp 和 input。
| 字段 | 类型 | 描述 |
|---|---|---|
id |
文本 | 个人数据。此人的 LinkedIn 个人资料唯一标识符 |
name |
文本 | 个人数据。个人资料姓名 |
city |
文本 | 用户的地理位置 |
country_code |
文本 | 用户的地理位置 |
position |
文本 | 该个人资料当前的职称或职位 |
about |
文本 | 个人数据。简要的个人资料摘要。在某些情况下,网站上只显示以“…”结尾的截断版本,我们采集的也是这个版本 |
posts |
数组 | 包含与用户最近发布的 LinkedIn 帖子有关的信息。通常包括帖子标题、创建日期、帖子 URL 链接等 |
groups |
数组 | 该个人资料所属的 LinkedIn 群组 |
current_company |
对象 | 提供用户当前职业职位的信息。通常包括公司名称、用户职称、公司 ID,以及公司所属的行业或领域 |
experience |
数组 | 包含用户职业经历的信息。通常包括用户职称、任职时长、公司的地理位置、开始和结束日期、公司名称、公司个人资料 URL 链接等 |
url |
URL | 个人数据。直接链接到 LinkedIn 个人资料的 URL |
people_also_viewed |
数组 | 提供一个 LinkedIn 个人资料列表,查看过该用户个人资料的用户也查看过这些个人资料 |
educations_details |
文本 | 提供用户教育背景的信息 |
education |
数组 | 提供用户教育背景的信息。通常包括学位、开始和结束年份、专业领域等 |
recommendations_count |
数字 | 用户收到的推荐总数 |
avatar |
URL | LinkedIn 用户头像的 URL 链接 |
courses |
数组 | 包含用户参加过的课程或教育项目的信息 |
languages |
数组 | 包含用户掌握不同语言程度的信息 |
certifications |
数组 | 许可证与认证 |
recommendations |
数组 | 用户从 LinkedIn 联系人或同事处收到的推荐 |
volunteer_experience |
数组 | 包含与用户志愿工作相关的信息 |
followers |
数字 | 关注该个人资料的用户/公司数量 |
connections |
数字 | 该个人资料拥有的联系人数量 |
current_company_company_id |
文本 | 该个人资料最新/当前公司的 ID |
current_company_name |
文本 | 该个人资料最新/当前公司的名称 |
publications |
数组 | 已发表的作品或演示文稿 |
patents |
数组 | 已申请或获批的专利 |
projects |
数组 | 职业或学术项目 |
organizations |
数组 | 专业组织成员资格 |
location |
文本 | 用户的地理位置 |
input_url |
URL | 个人数据。启动抓取流程时输入的 URL |
linkedin_id |
文本 | 个人数据。LinkedIn 个人资料标识符 |
activity |
数组 | 用户与帖子有关的任何活动 |
linkedin_num_id |
文本 | 数字形式的 LinkedIn 个人资料 ID |
banner_image |
URL | 横幅图片 |
honors_and_awards |
数组 | 获得的奖项和荣誉 |
similar_profiles |
数组 | 与当前个人资料相似的个人资料 |
default_avatar |
布尔值 | 头像是否为默认的空头像 |
memorialized_account |
布尔值 | 表示账户是否已设为纪念账户的布尔值 |
bio_links |
数组 | 添加到个人简介中的外部链接 |
first_name |
文本 | 个人数据。用户的名字 |
last_name |
文本 | 个人数据。用户的姓氏 |
urn_id |
文本 | LinkedIn 使用的统一资源名称(URN) |
urn |
文本 | 统一资源名称 |
influencer |
布尔值 | 个人资料是否被标记为影响者 |
fsd_profile_id |
文本 | FSD 个人资料 ID |
backfilled_columns |
对象 | 表示是否已回填固定列。键为列名,值为 true/false。 |
真实输出文件的开头,来自 linkedin-scraper satyanadella
{
"generated_at": "2026-09-18T14:15:08.047993+00:00",
"profiles": [
{
"slug": "satyanadella",
"profile": {
"id": "satyanadella",
"name": "Satya Nadella",
"city": "Redmond, Washington, United States",
"country_code": "US",
"position": "Chairman and CEO at Microsoft",
"about": "As chairman and CEO of Microsoft, I define my mission and that of my company as empowering every person and every organization on the planet to achieve more.",
"posts": [
{
"title": "How do we build a frontier intelligence ecosystem?",
"attribution": "Great to be back at Microsoft Build today. For us, it is not about any one piece of technology or even the platform.",
"img": "https://media.licdn.com/dms/image/v2/D560DAQHI1Iu8CrO8CQ/learning-public-crop_288_512/B56ZvrnmmhJ8AQ-/0/1769184586791?e=2147483647&v=beta&t=IZT3h7JK8tLoX5KYgwA0xLjxIKtc14hmHqKCk1cOLP8",
"link": "https://www.linkedin.com/pulse/how-do-we-build-frontier-intelligence-ecosystem-satya-nadella-73jhc",
"created_at": "2026-06-02T00:00:00.000Z",
...完整文件包含一份具有所有字段的个人资料,位于 examples/sample_output.json。
| 你看到的内容 | 含义 |
|---|---|
API token required but not found. |
在发出任何请求前以状态码 2 退出。请设置令牌。 |
failed slug: The profile is hidden or private. |
以状态码 1 退出。该个人资料不存在或未公开。通常是 slug 中有拼写错误。 |
failed slug: the API returned no row for this profile |
以状态码 1 退出。作业没有返回该输入对应的结果行。请重新运行。 |
failed slug: timeout |
以状态码 1 退出。请求在 180 秒后放弃。请重新运行。 |
failed slug: Failed to fetch results: Request timeout after 30 seconds |
以状态码 1 退出。作业已完成,但下载耗时超过 30 秒。请重新运行。 |
failed slug: Crawler error: Your system is sending too many of this type of request. ... |
以状态码 1 退出。账户正在被限流,有效的个人资料也会因此失败。请等待一段时间后重新运行。限制会自行解除。 |
任何失败都会以状态码 1 退出,因此可以安全地使用运行结果来控制脚本是否继续执行。
在 SDK 中,相同情况如下所示:
| 你看到的内容 | 含义 |
|---|---|
AuthenticationError: Unauthorized (401) |
令牌已设置,但不正确。 |
result.success 为 False,result.status 为 "timeout" |
SDK 放弃等待作业,默认等待时间为 180 秒。请向调用传递 timeout=420,或重新运行。 |
Failed to fetch results: Request timeout after 30 seconds |
作业已完成,但下载未完成。这是客户端对每个 HTTP 请求自身设置的限制,即 SyncBrightDataClient(timeout=30),并不是你传给调用的 timeout。提高调用的 timeout 没有帮助。请重新运行,或向客户端传递更大的 timeout。 |
result.data 中包含 error 键的字典 |
API 针对一个输入给出的响应。result.success 仍显示 True;请读取结果行本身。 |
无需 Python,也无需安装任何内容。粘贴这两行;第一行会打开一次浏览器,也可以通过 SSH 和 CI 使用 bdata login --device:
npx -p @brightdata/cli bdata login
npx -p @brightdata/cli bdata pipelines run gd_l1viktl72bvl7bjuj0 collect_by_url "https://www.linkedin.com/in/satyanadella/"bdata pipelines search linkedin 会查找所有爬虫工具及其 ID。LinkedIn 相关工具包括人员个人资料 gd_l1viktl72bvl7bjuj0、公司信息 gd_l1vikfnt1wgvvqz95w、职位列表 gd_lpfll7v5hcqtkxl6l、帖子 gd_lyy3tktm25m4avu764 和人员搜索 gd_m8d03he47z8nwb5xc。每项功能都通过 collect_by_url 接受 URL、输出 JSON,并且每条记录消耗一个额度。bdata pipelines info <id> 会列出爬虫工具的其他方法。
npx skills add brightdata/skills 会让 Claude Code、Cursor 和 Codex 学会这些命令及相关文档,之后即可使用自然语言操作。完整指南:面向编码智能体的 Bright Data。
使用托管助手且没有终端?Bright Data MCP 服务器在其 social 组中提供 LinkedIn 工具;除非你明确请求,否则该组处于关闭状态:
https://mcp.brightdata.com/mcp?token=YOUR_API_TOKEN&groups=social
智能体也可以自行开通账户,无需填写注册表单:智能体注册。Bright Data 支持的其他所有连接方式,从 LangChain 到 Zapier 和 n8n:集成。
新的 Bright Data 账户每月可获得 5,000 个免费额度。个人资料、公司、职位和帖子每条记录消耗一个额度,因此免费额度每月可抓取 5,000 份个人资料。定价列出了超出后的费率。
此仓库中的错误:提交 issue,并参阅 CONTRIBUTING.md 了解需要提供哪些信息。有关 API、你的账户或额度的任何问题,请联系 Bright Data 支持团队。
Node.js 也提供相同的 LinkedIn 爬虫工具:bright-cn/linkedin-scraper-node。
