关于 uspto-database
uspto-database 是供专利研究者和分析人员使用的 Python 技能,可查询 USPTO 相关专利数据。它涵盖 PatentsView 搜索和 Google Patents BigQuery 分析,适用于定向检索及专利组合、申请趋势分析。
主要功能
- 01按权利人和发明人搜索
- 02按 CPC 分类筛选
- 03搜索专利标题和摘要
- 04组合日期与查询条件
- 05使用 BigQuery 分析专利数据
适用场景
- 01为技术查找现有技术
- 02梳理竞争者的专利组合
- 03追踪不同技术的申请趋势
- 04识别某领域的发明人
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill uspto-database安装后在 Claude Code 中输入/uspto-database确认已加载。
详细介绍
uspto-database
概述
USPTO 提供两种主要的专利数据编程访问方式:PatentsView API(REST,免费,基本使用无需密钥),可按发明人、受让人、CPC 分类和关键词执行结构化查询;以及 Google Patents Public Data(BigQuery 公共数据集),可对完整专利语料进行大规模分析。两者提供的数据均采用 CC0 公共领域贡献协议。本技能介绍这两种方式的 Python 访问模式,以及基础的专利组合分析。
适用场景
- 现有技术检索:在提交申请前查找与某项技术相关的现有专利,或评估实施自由。
- 竞争对手知识产权格局分析:查询特定受让人(公司或机构)的所有专利,以绘制其技术组合。
- CPC 分类检索:使用合作专利分类代码查找特定技术领域的专利(例如,C12N 表示核苷酸/基因工程)。
- 发明人网络分析:识别某个领域中的高产发明人及其机构所属关系。
- 技术趋势追踪:按年份和技术类别统计专利申请数量,以识别新兴领域。
- 生命科学知识产权分析:检索生物技术专属分类(A61K 表示药品,C12N 表示遗传学,G16B 表示生物信息学)。
- 如需下载专利全文 PDF,请使用 USPTO Bulk Data Storage System(BDSS)或 Google Patents 直链。
- 速率限制:PatentsView API 在未使用 API 密钥时每分钟允许 45 次请求;申请免费密钥后,每分钟仍为 45 次请求,但每日限额更高。
前置条件
- Python 包:
requests、pandas、matplotlib - 可选:使用 Google Patents Public Data 查询时需要
google-cloud-bigquery - 数据要求:PatentsView 基本查询无需账号;BigQuery 需要 Google Cloud 账号
- 速率限制:PatentsView——每分钟 45 次请求(未经身份验证),使用免费 API 密钥后限额更高
pip install requests pandas matplotlib
pip install google-cloud-bigquery # optional: for BigQuery access
快速开始
import requests
import pandas as pd
# Search PatentsView API: patents assigned to "Genentech" in CPC class C12N
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"_and": [
{"_contains": {"assignee_organization": "Genentech"}},
{"_contains": {"cpc_subgroup_id": "C12N"}},
]},
"f": ["patent_number", "patent_title", "patent_date", "assignee_organization"],
"o": {"per_page": 25},
}
resp = requests.post(url, json=payload)
data = resp.json()
df = pd.DataFrame(data["patents"])
print(f"Found: {data['total_patent_count']} patents")
print(df[["patent_number", "patent_title", "patent_date"]].head())
核心 API
查询类型 1:按受让人(公司/机构)检索
查找授予特定组织的所有专利。
import requests
import pandas as pd
def search_by_assignee(assignee_name: str, per_page: int = 100) -> pd.DataFrame:
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"_contains": {"assignee_organization": assignee_name}},
"f": [
"patent_number", "patent_title", "patent_date",
"patent_abstract", "assignee_organization", "assignee_country",
],
"o": {"per_page": per_page, "sort": [{"patent_date": "desc"}]},
}
resp = requests.post(url, json=payload)
resp.raise_for_status()
data = resp.json()
df = pd.DataFrame(data.get("patents", []))
print(f"Assignee '{assignee_name}': {data.get('total_patent_count', 0)} total patents")
return df
# Example: patents from Broad Institute
df_broad = search_by_assignee("Broad Institute")
print(df_broad[["patent_number", "patent_title", "patent_date"]].head(10))
# Paginate through all results for large portfolios
def search_assignee_all_pages(assignee_name: str, page_size: int = 100) -> pd.DataFrame:
url = "https://api.patentsview.org/patents/query"
all_patents = []
page = 1
while True:
payload = {
"q": {"_contains": {"assignee_organization": assignee_name}},
"f": ["patent_number", "patent_title", "patent_date", "cpc_subgroup_id"],
"o": {"per_page": page_size, "page": page},
}
resp = requests.post(url, json=payload)
data = resp.json()
patents = data.get("patents", [])
if not patents:
break
all_patents.extend(patents)
total = data.get("total_patent_count", 0)
if len(all_patents) >= total:
break
page += 1
df = pd.DataFrame(all_patents)
print(f"Retrieved {len(df)} patents for '{assignee_name}'")
return df
查询类型 2:按 CPC 分类检索
CPC(合作专利分类)代码用于按技术领域组织专利。生命科学代码包括 C12N(核苷酸/遗传学)、A61K(药品)和 G16B(生物信息学)。
import requests
import pandas as pd
# Search by CPC subgroup: C12N15 (mutation/genetic engineering)
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"_begins": {"cpc_subgroup_id": "C12N15"}},
"f": [
"patent_number", "patent_title", "patent_date",
"assignee_organization", "cpc_subgroup_id",
],
"o": {"per_page": 50, "sort": [{"patent_date": "desc"}]},
}
resp = requests.post(url, json=payload)
data = resp.json()
df = pd.DataFrame(data["patents"])
print(f"C12N15 patents: {data['total_patent_count']}")
print(df[["patent_number", "patent_title", "assignee_organization"]].head(10))
# Common life sciences CPC codes
CPC_LIFE_SCIENCES = {
"C12N": "Microorganisms / enzymes / compositions",
"C12N15": "Mutation / genetic engineering",
"C12Q": "Measuring / testing involving enzymes or microorganisms",
"A61K": "Preparations for medical use",
"A61P": "Therapeutic activity of chemical compounds",
"G16B": "Bioinformatics",
"G16H": "Healthcare informatics",
"C07K": "Peptides / proteins",
}
for code, desc in CPC_LIFE_SCIENCES.items():
print(f" {code:10s}: {desc}")
查询类型 3:全文关键词检索
在专利标题和摘要中搜索特定词语。
import requests
import pandas as pd
def keyword_search(keyword: str, per_page: int = 50) -> pd.DataFrame:
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"_or": [
{"_text_any": {"patent_title": keyword}},
{"_text_any": {"patent_abstract": keyword}},
]},
"f": [
"patent_number", "patent_title", "patent_date",
"patent_abstract", "assignee_organization",
],
"o": {"per_page": per_page, "sort": [{"patent_date": "desc"}]},
}
resp = requests.post(url, json=payload)
resp.raise_for_status()
data = resp.json()
df = pd.DataFrame(data.get("patents", []))
print(f"Keyword '{keyword}': {data.get('total_patent_count', 0)} patents found")
return df
# Search for CRISPR-related patents
df_crispr = keyword_search("CRISPR")
print(df_crispr[["patent_number", "patent_title", "patent_date"]].head(10))
查询类型 4:按发明人检索
按发明人姓名查找专利,或检索发明人的完整出版记录。
import requests
import pandas as pd
# Search by inventor name
url = "https://api.patentsview.org/inventors/query"
payload = {
"q": {"_and": [
{"inventor_last_name": "Doudna"},
{"inventor_first_name": "Jennifer"},
]},
"f": ["inventor_id", "inventor_first_name", "inventor_last_name",
"inventor_city", "inventor_state", "inventor_country"],
"o": {"per_page": 10},
}
resp = requests.post(url, json=payload)
data = resp.json()
print(f"Found {data.get('total_inventor_count', 0)} inventors matching 'Jennifer Doudna'")
for inv in data.get("inventors", []):
print(f" ID: {inv['inventor_id']}, Location: {inv.get('inventor_city')}, {inv.get('inventor_country')}")
# Get all patents for a specific inventor by inventor_id
inventor_id = "fl:j_ln:doudna-1" # PatentsView inventor ID format
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"inventor_id": inventor_id},
"f": ["patent_number", "patent_title", "patent_date", "assignee_organization"],
"o": {"per_page": 100, "sort": [{"patent_date": "desc"}]},
}
resp = requests.post(url, json=payload)
data = resp.json()
df = pd.DataFrame(data.get("patents", []))
print(f"Patents for inventor {inventor_id}: {data.get('total_patent_count', 0)}")
print(df.head(5))
查询类型 5:日期范围和组合筛选条件
组合多个筛选条件,执行针对性检索。
import requests
import pandas as pd
# Patents in gene therapy (CPC A61K48) filed 2020-2024 by a US assignee
url = "https://api.patentsview.org/patents/query"
payload = {
"q": {"_and": [
{"_begins": {"cpc_subgroup_id": "A61K48"}},
{"_gte": {"patent_date": "2020-01-01"}},
{"_lte": {"patent_date": "2024-12-31"}},
{"_eq": {"assignee_country": "US"}},
]},
"f": [
"patent_number", "patent_title", "patent_date",
"assignee_organization", "patent_num_claims",
],
"o": {"per_page": 100, "sort": [{"patent_date": "desc"}]},
}
resp = requests.post(url, json=payload)
data = resp.json()
df = pd.DataFrame(data.get("patents", []))
print(f"Gene therapy patents 2020-2024 (US assignee): {data.get('total_patent_count', 0)}")
print(df[["patent_number", "patent_title", "patent_date", "assignee_organization"]].head(10))
查询类型 6:Google Patents BigQuery
如需对专利语料进行大规模分析,请使用 BigQuery 中的 Google Patents 公共数据集。
from google.cloud import bigquery
client = bigquery.Client(project="YOUR_GCP_PROJECT")
# Count CRISPR patents by year (Google Patents public data)
query = """
SELECT
EXTRACT(YEAR FROM filing_date) AS filing_year,
COUNT(*) AS patent_count,
COUNT(DISTINCT assignee) AS unique_assignees
FROM `patents-public-data.patents.publications`
WHERE
(LOWER(title_localized[SAFE_OFFSET(0)].text) LIKE '%crispr%'
OR LOWER(abstract_localized[SAFE_OFFSET(0)].text) LIKE '%crispr%')
AND filing_date >= '2010-01-01'
AND country_code = 'US'
GROUP BY filing_year
ORDER BY filing_year
"""
df_bq = client.query(query).to_dataframe()
print(df_bq)
print(f"Peak year: {df_bq.loc[df_bq.patent_count.idxmax(), 'filing_year']} "
f"({df_bq.patent_count.max()} patents)")
关键参数
| 参数 | 模块 | 默认值 | 范围/选项 | 作用 |
|---|---|---|---|---|
per_page | PatentsView "o" | 25 | 1–10000 | 每次 API 调用返回的结果数 |
page | PatentsView "o" | 1 | 1–最大页数 | 分页时的页码 |
sort | PatentsView "o" | API 默认值 | 任意字段 + "asc"/"desc" | 结果排序方式 |
"f" 字段 | PatentsView | 最少字段 | 任意有效字段列表 | 响应中返回的字段(控制载荷大小) |
"_begins" | 查询运算符 | — | 字段 + 前缀字符串 | 前缀匹配(例如,CPC 代码前缀) |
"_contains" | 查询运算符 | — | 字段 + 子字符串 | 子字符串搜索(不区分大小写) |
"_text_any" | 查询运算符 | — | 字段 + 关键词 | 对标题/摘要字段进行全文搜索 |
最佳实践
-
仅请求所需字段:「
"f"(字段)参数控制返回的内容。为数千项专利请求patent_abstract会显著增加载荷大小和延迟。 -
处理大型结果集时,始终进行分页:PatentsView 将每页响应上限设为 10,000 条。对于返回结果超过 10,000 条的查询,请按日期范围拆分,或缩小 CPC 代码范围以拆分查询。
-
将 API 响应缓存到磁盘:PatentsView 有速率限制;如果要迭代构建数据集,请在每次 API 调用后将响应保存为 JSON/CSV。
import json, pathlib cache = pathlib.Path("cache") cache.mkdir(exist_ok=True) cache_file = cache / "genentech_patents.json" if not cache_file.exists(): resp = requests.post(url, json=payload) cache_file.write_text(resp.text) data = json.loads(cache_file.read_text()) -
针对特定技术的搜索使用 CPC 代码,而不仅是关键词:关键词会漏掉同义词和外语专利;专利审查员会分配 CPC 代码,因此这种方式更系统。
-
验证受让人名称:专利记录中的公司名称可能有所不同(例如「Genentech Inc.」「Genentech, Inc.」「GENENTECH INC」)。使用
_contains进行模糊匹配,然后在 pandas 中去重。
常见工作流
工作流 1:技术格局分析——按年份统计申请趋势
目标:统计某个 CPC 类别中每年的专利申请数量,并绘制趋势图。
import requests
import pandas as pd
import matplotlib.pyplot as plt
from collections import defaultdict
def count_patents_by_year(cpc_prefix: str, start_year: int = 2010) -> pd.DataFrame:
url = "https://api.patentsview.org/patents/query"
counts = defaultdict(int)
page = 1
while True:
payload = {
"q": {"_and": [
{"_begins": {"cpc_subgroup_id": cpc_prefix}},
{"_gte": {"patent_date": f"{start_year}-01-01"}},
]},
"f": ["patent_number", "patent_date"],
"o": {"per_page": 10000, "page": page},
}
resp = requests.post(url, json=payload)
patents = resp.json().get("patents", [])
if not patents:
break
for p in patents:
year = p["patent_date"][:4]
counts[year] += 1
total = resp.json().get("total_patent_count", 0)
if sum(counts.values()) >= total:
break
page += 1
df = pd.DataFrame(sorted(counts.items()), columns=["year", "count"])
return df
df_trend = count_patents_by_year("C12N15", start_year=2010)
fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(df_trend["year"], df_trend["count"], color="steelblue", edgecolor="white")
ax.set_xlabel("Year")
ax.set_ylabel("Patents granted")
ax.set_title("US Patents: C12N15 (Genetic Engineering) by Year")
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig("cpc_trend.png", dpi=150)
print(f"Trend plotted: {df_trend['count'].sum()} total patents -> cpc_trend.png")
工作流 2:受让人专利组合对比
目标:比较目标 CPC 类别中多家生物技术公司的专利数量。
import requests
import pandas as pd
import matplotlib.pyplot as plt
def count_patents_by_assignee(assignees: list, cpc_prefix: str) -> pd.DataFrame:
url = "https://api.patentsview.org/patents/query"
records = []
for assignee in assignees:
payload = {
"q": {"_and": [
{"_contains": {"assignee_organization": assignee}},
{"_begins": {"cpc_subgroup_id": cpc_prefix}},
]},
"f": ["patent_number"],
"o": {"per_page": 1}, # only need total count
}
resp = requests.post(url, json=payload)
total = resp.json().get("total_patent_count", 0)
records.append({"assignee": assignee, "patent_count": total})
print(f" {assignee}: {total} patents")
df = pd.DataFrame(records).sort_values("patent_count", ascending=True)
return df
companies = ["Genentech", "Amgen", "Regeneron", "AstraZeneca", "Novartis"]
df_comp = count_patents_by_assignee(companies, cpc_prefix="A61K")
fig, ax = plt.subplots(figsize=(7, 4))
ax.barh(df_comp["assignee"], df_comp["patent_count"], color="salmon")
ax.set_xlabel("Patent count (A61K)")
ax.set_title("Pharmaceutical Patents by Assignee (CPC A61K)")
plt.tight_layout()
plt.savefig("assignee_comparison.png", dpi=150)
print("Comparison chart saved -> assignee_comparison.png")
预期输出
- 包含专利记录的
pd.DataFrame(列取决于请求的"f"字段) cpc_trend.png— 按年份统计专利数量的柱状图assignee_comparison.png— 对比各公司的横向柱状图- API 响应中的
total_patent_count给出查询对应的完整语料规模
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
HTTPError 429 Too Many Requests | 超出每分钟 45 次请求的速率限制 | 在请求之间添加 time.sleep(1.5);申请免费的 API 密钥 |
响应中的 patents 列表为空 | 查询范围太窄或字段名称不正确 | 检查 PatentsView API 文档中的字段名称;先在网页界面中测试查询 |
| 结果中缺少已知专利 | 对受让人名称进行精确字符串匹配 | 使用 _contains 而不是 _eq;检查名称变体 |
KeyError: patent_date | "f" 列表中未请求该字段 | 将 "patent_date" 添加到 "f" 数组 |
| BigQuery 身份验证错误 | 未配置 GCP 凭据 | 运行 gcloud auth application-default login 或设置 GOOGLE_APPLICATION_CREDENTIALS |
| CPC 前缀未返回结果 | CPC 代码无效或有拼写错误 | 在 CPC 分类浏览器中验证代码 |
参考资料
- PatentsView API 文档 — 完整字段列表和查询运算符参考
- PatentsView API 浏览器 — 用于测试的浏览器端查询构建器
- Google Patents 公共数据(BigQuery) — 架构文档
- CPC 分类浏览器 — 浏览生命科学领域的 CPC 代码
- USPTO 批量数据存储系统 — 专利全文 XML 下载