Edu APIjgw.aynu.edu.cn ↗
Access oracle bone inscriptions, characters, radicals, and collections from the Yinqi Wenyuan database at Anyang Normal University via a structured REST API.
What is the Edu API?
This API exposes 5 endpoints covering the Yinqi Wenyuan (殷契文渊) digital platform's oracle bone inscription database, including paginated rubbing searches, character font lookups, and radical indices. The search_inscriptions endpoint returns image URLs, piece numbers, and source metadata for entries in the 著录库, while search_characters provides Unicode IDs, pinyin, and traditional and simplified meanings for oracle bone script characters.
curl -X GET 'https://api.parse.bot/scraper/5a3d513d-906e-4de4-9455-65d043c4f1de/search_inscriptions?page=2&query=%E6%8B%BC' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace jgw-aynu-edu-cn-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
Yinqi Wenyuan Oracle Bone API Client
This module provides a Python client for accessing oracle bone inscription data
from the Yinqi Wenyuan digital platform at Anyang Normal University.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Dict, Any, List
class ParseClient:
"""Client for interacting with the Yinqi Wenyuan Oracle Bone API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the ParseClient.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "5a3d513d-906e-4de4-9455-65d043c4f1de"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError(
"API key not provided. Set PARSE_API_KEY environment variable or pass api_key parameter."
)
def _call(
self, endpoint: str, method: str = "POST", **params
) -> Dict[str, Any]:
"""
Make an API call to the Parse service.
Args:
endpoint: The API endpoint name
method: HTTP method (GET or POST)
**params: Query/body parameters
Returns:
Parsed JSON response as dictionary
Raises:
requests.exceptions.RequestException: If the request fails
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_inscriptions(
self, query: str, book_code: Optional[str] = None, page: int = 1
) -> Dict[str, Any]:
"""
Search for oracle bone inscriptions in the collection database.
Args:
query: Search term for inscription name (e.g. '合', '拼')
book_code: Optional filter by collection code (e.g. '010001H')
page: Page number for pagination (default: 1)
Returns:
Dictionary with 'items' (inscriptions) and 'pagination' info
"""
params = {"query": query, "page": page}
if book_code:
params["book_code"] = book_code
return self._call("search_inscriptions", method="GET", **params)
def search_characters(
self, query: str, type: int = 1
) -> Dict[str, Any]:
"""
Search for oracle bone characters in the font database.
Args:
query: Search term - Chinese character (type=1) or pinyin string (type=3)
type: Search type - 1 for character lookup, 3 for pinyin lookup (default: 1)
Returns:
Dictionary with 'items' containing character objects
"""
return self._call(
"search_characters", method="GET", query=query, type=type
)
def get_character_detail(self, unicode_id: str) -> Dict[str, Any]:
"""
Get detailed information for a specific oracle bone character.
Args:
unicode_id: Unicode ID of the character (e.g. 'U608C1')
Returns:
Dictionary with character details including sources and related characters
"""
return self._call("get_character_detail", method="GET", unicode_id=unicode_id)
def get_collections(self) -> Dict[str, Any]:
"""
List all available oracle bone collections and books.
Returns:
Dictionary with 'collections' array containing collection metadata
"""
return self._call("get_collections", method="GET")
def get_radicals(self) -> Dict[str, Any]:
"""
List radicals used for indexing characters in the oracle bone font database.
Returns:
Dictionary with 'radicals' array containing radical identifiers
"""
return self._call("get_radicals", method="GET")
def main():
"""
Practical workflow demonstrating the Oracle Bone API client.
This example shows a realistic use case:
1. Get available collections
2. Search for inscriptions containing a specific character
3. For each inscription found, retrieve character details
4. Display comprehensive information about the findings
"""
# Initialize the client
client = ParseClient()
print("=" * 70)
print("YINQI WENYUAN ORACLE BONE API - PRACTICAL WORKFLOW")
print("=" * 70)
# Step 1: Get available collections
print("\n[Step 1] Fetching available oracle bone collections...")
collections_response = client.get_collections()
collections = collections_response.get("data", {}).get("collections", [])
print(f"Found {len(collections)} collections:")
for collection in collections[:5]: # Show first 5
print(f" - {collection['name']} (Code: {collection['code']})")
if len(collections) > 5:
print(f" ... and {len(collections) - 5} more")
# Step 2: Search for inscriptions with a common oracle bone character
print("\n[Step 2] Searching for inscriptions containing '合' (he)...")
search_query = "合"
inscriptions_response = client.search_inscriptions(
query=search_query, page=1
)
items = inscriptions_response.get("data", {}).get("items", [])
pagination = inscriptions_response.get("data", {}).get("pagination", {})
print(
f"Found {pagination.get('total_count', 0)} total inscriptions "
f"(showing page {pagination.get('current_page', 1)} of {pagination.get('total_pages', 0)})"
)
print(f"Sample inscriptions on this page: {len(items)}")
# Step 3: Search for the character in the character database
print(f"\n[Step 3] Looking up character details for '{search_query}'...")
char_search_response = client.search_characters(query=search_query, type=1)
characters = char_search_response.get("data", {}).get("items", [])
print(f"Found {len(characters)} character entry(ies):")
# Step 4: Get detailed information for each character found
for idx, char in enumerate(characters[:3], 1): # Show details for first 3
unicode_id = char.get("unicode_id")
meaning = char.get("meaning_traditional", "N/A")
pinyin = char.get("pinyin", "N/A")
bone_ref = char.get("bone_reference", "N/A")
print(f"\n Character {idx}: {unicode_id}")
print(f" Meaning: {meaning}")
print(f" Pinyin: {pinyin}")
print(f" Oracle Bone Reference: {bone_ref}")
# Get full details for this character
if unicode_id:
try:
detail_response = client.get_character_detail(unicode_id)
detail = detail_response.get("data", {})
sources = detail.get("sources", [])
related = detail.get("related_chars", "")
if sources:
print(f" Sources: {len(sources)} reference(s)")
for source in sources[:2]:
print(
f" - Type {source.get('type_code')}: {source.get('content')}"
)
if len(sources) > 2:
print(f" ... and {len(sources) - 2} more")
if related:
print(f" Related Characters: {related[:50]}...")
except Exception as e:
print(f" (Could not retrieve full details: {str(e)})")
# Step 5: Display inscription sample data
print("\n[Step 4] Sample inscriptions retrieved:")
for idx, inscription in enumerate(items[:3], 1): # Show first 3
print(f"\n Inscription {idx}:")
print(f" ID: {inscription.get('id')}")
print(f" Name: {inscription.get('name')}")
print(f" Type: {inscription.get('type')}")
print(f" Source: {inscription.get('source')}")
print(f" Image: {inscription.get('image_url', 'N/A')[:60]}...")
print("\n" + "=" * 70)
print("Workflow complete!")
print("=" * 70)
if __name__ == "__main__":
main()Search for oracle bone inscriptions (rubbings/bones) in the 著录库 database. Returns paginated results with basic metadata and image URLs.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number for pagination. |
| queryrequired | string | Search term for inscription name/片号 (e.g. '合', '拼') |
| book_code | string | Filter by collection/book code from get_collections endpoint (e.g. '010001H'). Omitting returns results across all collections. |
{
"type": "object",
"fields": {
"items": "array of inscription objects with id, name, number, type, source, image_url, and detail_url_path",
"pagination": "object with current_page, total_count, and total_pages"
},
"sample": {
"data": {
"items": [
{
"id": "108547",
"name": "合1",
"type": "拓片",
"number": "",
"source": "甲骨文合集",
"image_url": "http://jgw.aynu.edu.cn/File/GetFirstSmallPic?dbId=34&recordId=108547&key=K5U3keEBpCT1f3TdQSh1hw%3d%3d",
"detail_url_path": "/Detail?dbID=34&dbName=BONE&sysID=108547"
}
],
"pagination": {
"total_count": 61552,
"total_pages": 5130,
"current_page": 1
}
},
"status": "success"
}
}About the Edu API
Inscription and Collection Data
The search_inscriptions endpoint queries the 著录库 rubbing database. Required parameter query accepts a piece-number fragment or name (for example 合 or 拼). Optional book_code narrows results to a specific collection; valid codes come from the get_collections endpoint, which returns every collection's id, name, code, and grade. Each inscription result includes id, name, number, type, source, an image_url for the rubbing scan, and a detail_url_path. Pagination is handled via the page parameter; the response's pagination object exposes current_page, total_count, and total_pages.
Character Font Database
The search_characters endpoint queries the 字形库. Set type=1 to search by a modern Chinese character or type=3 to search by pinyin string. Results include unicode_id, oracle_bone_char_hex, meaning_traditional, meaning_simplified, pinyin, and bone_reference. For deeper detail, pass a unicode_id (for example U608C1) to get_character_detail, which returns the character's citation sources array (each with type_code and content), related_chars as a comma-separated string of related IDs, and oracle_bone_char_hex where available.
Radicals Index
The get_radicals endpoint returns the full list of radical identifiers used to index oracle bone characters. Each entry carries a code (hex string) and a name in U-prefixed format, reflecting Unicode Private Use Area assignments used by the platform's font system. These codes align with the unicode_id values returned by search_characters and get_character_detail, making them useful for building radical-based browsing or filtering logic on top of the character endpoints.
The Edu API is a managed, monitored endpoint for jgw.aynu.edu.cn — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when jgw.aynu.edu.cn changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official jgw.aynu.edu.cn API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a searchable index of oracle bone rubbing images using
image_urland piece-number fields fromsearch_inscriptions. - Map modern Chinese characters to their oracle bone script forms by combining
search_charactersmeaning_traditionalandoracle_bone_char_hexfields. - Generate a radical-browsing interface for oracle bone script using codes from
get_radicalsas navigation anchors. - Filter inscription searches by specific published collections using
book_codevalues retrieved fromget_collections. - Build a citation reference tool using
sourcesarrays fromget_character_detailto trace scholarly references for individual characters. - Cross-reference related oracle bone characters by parsing the
related_charsfield returned inget_character_detail. - Support linguistic research tools by exposing
pinyinandbone_referencedata alongside traditional/simplified meanings fromsearch_characters.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Yinqi Wenyuan (jgw.aynu.edu.cn) offer an official developer API?+
What does `get_character_detail` return beyond what `search_characters` provides?+
search_characters gives summary fields: unicode_id, oracle_bone_char_hex, meaning_traditional, meaning_simplified, pinyin, and bone_reference. get_character_detail adds a sources array with per-citation type_code and content entries, a related_chars comma-separated list, and the full oracle_bone_char_hex where available — useful when you need scholarly citation data rather than just the character summary.Can I retrieve the full rubbing detail page for an inscription, not just summary metadata?+
search_inscriptions endpoint returns summary-level fields including image_url and detail_url_path, but does not currently expose a dedicated detail endpoint that returns transcription text, excavation metadata, or associated interpretations for individual rubbings. The API covers inscription search results and collection listings. You can fork it on Parse and revise it to add a rubbing detail endpoint covering those additional fields.Is there a way to browse all inscriptions in a collection without a search term?+
search_inscriptions requires a query string; it does not support open-ended browsing that returns all entries in a collection when no search term is provided. You can retrieve valid book_code values from get_collections and pair them with a broad query term to narrow scope, but full collection enumeration without a query is not currently supported. You can fork this API on Parse and revise it to add an endpoint that lists all inscriptions for a given collection code.How does pagination work in `search_inscriptions`?+
page parameter to move through result pages. Each response includes a pagination object with current_page, total_count, and total_pages, so you can iterate through all results programmatically without guessing the total number of pages.