mcpField
U
uspto-database

uspto-database

github.com/jaechang-hits数据与数据库38469 次安装1 周前更新
代码仓库

关于 uspto-database

uspto-database 是供专利研究者和分析人员使用的 Python 技能,可查询 USPTO 相关专利数据。它涵盖 PatentsView 搜索和 Google Patents BigQuery 分析,适用于定向检索及专利组合、申请趋势分析。

主要功能

  1. 01按权利人和发明人搜索
  2. 02按 CPC 分类筛选
  3. 03搜索专利标题和摘要
  4. 04组合日期与查询条件
  5. 05使用 BigQuery 分析专利数据

适用场景

  1. 01为技术查找现有技术
  2. 02梳理竞争者的专利组合
  3. 03追踪不同技术的申请趋势
  4. 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_pagePatentsView "o"251–10000每次 API 调用返回的结果数
pagePatentsView "o"11–最大页数分页时的页码
sortPatentsView "o"API 默认值任意字段 + "asc"/"desc"结果排序方式
"f" 字段PatentsView最少字段任意有效字段列表响应中返回的字段(控制载荷大小)
"_begins"查询运算符—字段 + 前缀字符串前缀匹配(例如,CPC 代码前缀)
"_contains"查询运算符—字段 + 子字符串子字符串搜索(不区分大小写)
"_text_any"查询运算符—字段 + 关键词对标题/摘要字段进行全文搜索

最佳实践

  1. 仅请求所需字段:「"f"(字段)参数控制返回的内容。为数千项专利请求 patent_abstract 会显著增加载荷大小和延迟。

  2. 处理大型结果集时,始终进行分页:PatentsView 将每页响应上限设为 10,000 条。对于返回结果超过 10,000 条的查询,请按日期范围拆分,或缩小 CPC 代码范围以拆分查询。

  3. 将 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())
    
  4. 针对特定技术的搜索使用 CPC 代码,而不仅是关键词:关键词会漏掉同义词和外语专利;专利审查员会分配 CPC 代码,因此这种方式更系统。

  5. 验证受让人名称:专利记录中的公司名称可能有所不同(例如「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 分类浏览器中验证代码

参考资料

评论

支持 Markdown