This workflow follows the Execute Workflow Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "XHS-Extraction",
"nodes": [
{
"parameters": {},
"id": "workflow-trigger",
"name": "Workflow Input",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
0,
300
]
},
{
"parameters": {
"jsCode": "// Extract topic records from input\nconst records = $input.first().json.records || [];\n\nif (records.length === 0) {\n return [{ json: { success: false, message: 'No records to process' } }];\n}\n\n// Map to individual items\nreturn records.map(record => ({\n json: {\n record_id: record.record_id,\n note_id: record.fields?.note_id || '',\n title: record.fields?.title || '',\n keyword_id: record.fields?.keyword_id || ''\n }\n}));"
},
"id": "extract-topics",
"name": "Extract Topics",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
200,
300
]
},
{
"parameters": {
"method": "PUT",
"url": "=https://open.feishu.cn/open-apis/bitable/v1/apps/{{ $env.LARK_APP_TOKEN }}/tables/{{ $env.TOPICS_TABLE_ID }}/records/{{ $json.record_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"fields\": {\n \"status\": \"\u63d0\u53d6\u4e2d\",\n \"locked_at\": \"{{ $now.toISO() }}\"\n }\n}",
"options": {}
},
"id": "lock-record",
"name": "Lock Record (\u63d0\u53d6\u4e2d)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
400,
300
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.CRAWLER_API_URL }}/api/note/detail",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"note_ids\": [\"{{ $('Extract Topics').item.json.note_id }}\"]\n}",
"options": {
"timeout": 30000
}
},
"id": "get-note-detail",
"name": "Get Note Detail",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
600,
300
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-success",
"leftValue": "={{ $json.success }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
},
{
"id": "has-items",
"leftValue": "={{ $json.data?.items?.length > 0 }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-detail-success",
"name": "IF Detail Success",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
800,
300
]
},
{
"parameters": {
"jsCode": "// Transform note detail to Source record\nconst detailResult = $input.first().json;\nconst noteDetail = detailResult.data?.items?.[0] || {};\nconst topicRecordId = $('Extract Topics').item.json.record_id;\nconst noteId = $('Extract Topics').item.json.note_id;\n\n// Extract content\nconst sourceRecord = {\n fields: {\n topic_id: topicRecordId,\n note_id: noteId,\n title: noteDetail.title || noteDetail.display_title || '',\n content: noteDetail.desc || noteDetail.note_desc || '',\n note_type: noteDetail.type === 'video' ? '\u89c6\u9891' : '\u56fe\u6587',\n images: JSON.stringify(noteDetail.image_list || noteDetail.images || []),\n video_url: noteDetail.video?.url || '',\n likes: noteDetail.liked_count || noteDetail.likes || 0,\n collects: noteDetail.collected_count || noteDetail.collects || 0,\n comments: noteDetail.comment_count || noteDetail.comments || 0,\n shares: noteDetail.share_count || noteDetail.shares || 0,\n author_id: noteDetail.user?.user_id || '',\n author_name: noteDetail.user?.nickname || '',\n author_avatar: noteDetail.user?.avatar || '',\n tags: JSON.stringify(noteDetail.tag_list || []),\n status: '\u5f85\u751f\u6210',\n extracted_at: new Date().toISOString()\n }\n};\n\nreturn [{ json: sourceRecord }];"
},
"id": "transform-to-source",
"name": "Transform to Source",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1000,
200
]
},
{
"parameters": {
"method": "POST",
"url": "=https://open.feishu.cn/open-apis/bitable/v1/apps/{{ $env.LARK_APP_TOKEN }}/tables/{{ $env.SOURCE_TABLE_ID }}/records",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"id": "create-source",
"name": "Create Source Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1200,
200
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "PUT",
"url": "=https://open.feishu.cn/open-apis/bitable/v1/apps/{{ $env.LARK_APP_TOKEN }}/tables/{{ $env.TOPICS_TABLE_ID }}/records/{{ $('Extract Topics').item.json.record_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"fields\": {\n \"status\": \"\u5df2\u63d0\u53d6\",\n \"locked_at\": null\n }\n}",
"options": {}
},
"id": "update-topic-success",
"name": "Update Topic (\u5df2\u63d0\u53d6)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1400,
200
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Handle extraction failure\nconst error = $input.first().json;\nreturn [{ json: {\n success: false,\n record_id: $('Extract Topics').item.json.record_id,\n note_id: $('Extract Topics').item.json.note_id,\n error: error.error?.message || 'Note detail not available'\n} }];"
},
"id": "handle-error",
"name": "Handle Error",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1000,
400
]
},
{
"parameters": {
"method": "PUT",
"url": "=https://open.feishu.cn/open-apis/bitable/v1/apps/{{ $env.LARK_APP_TOKEN }}/tables/{{ $env.TOPICS_TABLE_ID }}/records/{{ $json.record_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"fields\": {\n \"status\": \"\u63d0\u53d6\u5931\u8d25\",\n \"error_message\": \"{{ $json.error }}\",\n \"locked_at\": null\n }\n}",
"options": {}
},
"id": "update-topic-failed",
"name": "Update Topic (\u63d0\u53d6\u5931\u8d25)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1200,
400
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {},
"id": "merge-results",
"name": "Merge Results",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1600,
300
]
},
{
"parameters": {
"jsCode": "// Prepare output summary\nconst results = $input.all();\nlet successCount = 0;\nlet failCount = 0;\n\nfor (const item of results) {\n if (item.json.success !== false) {\n successCount++;\n } else {\n failCount++;\n }\n}\n\nreturn [{ json: {\n action: 'extraction',\n success: failCount === 0,\n topics_processed: results.length,\n sources_created: successCount,\n failed: failCount,\n message: `Extracted ${successCount} notes, ${failCount} failed`\n} }];"
},
"id": "prepare-output",
"name": "Prepare Output",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1800,
300
]
}
],
"connections": {
"Workflow Input": {
"main": [
[
{
"node": "Extract Topics",
"type": "main",
"index": 0
}
]
]
},
"Extract Topics": {
"main": [
[
{
"node": "Lock Record (\u63d0\u53d6\u4e2d)",
"type": "main",
"index": 0
}
]
]
},
"Lock Record (\u63d0\u53d6\u4e2d)": {
"main": [
[
{
"node": "Get Note Detail",
"type": "main",
"index": 0
}
]
]
},
"Get Note Detail": {
"main": [
[
{
"node": "IF Detail Success",
"type": "main",
"index": 0
}
]
]
},
"IF Detail Success": {
"main": [
[
{
"node": "Transform to Source",
"type": "main",
"index": 0
}
],
[
{
"node": "Handle Error",
"type": "main",
"index": 0
}
]
]
},
"Transform to Source": {
"main": [
[
{
"node": "Create Source Record",
"type": "main",
"index": 0
}
]
]
},
"Create Source Record": {
"main": [
[
{
"node": "Update Topic (\u5df2\u63d0\u53d6)",
"type": "main",
"index": 0
}
]
]
},
"Update Topic (\u5df2\u63d0\u53d6)": {
"main": [
[
{
"node": "Merge Results",
"type": "main",
"index": 0
}
]
]
},
"Handle Error": {
"main": [
[
{
"node": "Update Topic (\u63d0\u53d6\u5931\u8d25)",
"type": "main",
"index": 0
}
]
]
},
"Update Topic (\u63d0\u53d6\u5931\u8d25)": {
"main": [
[
{
"node": "Merge Results",
"type": "main",
"index": 1
}
]
]
},
"Merge Results": {
"main": [
[
{
"node": "Prepare Output",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner"
},
"staticData": null,
"tags": [
{
"name": "XHS-Pipeline",
"id": "xhs-pipeline"
}
],
"meta": {
"templateCredsSetupCompleted": true
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
XHS-Extraction. Uses executeWorkflowTrigger, httpRequest. Event-driven trigger; 12 nodes.
Source: https://github.com/wade56754/XHS/blob/b5b999f35721bcfe8ffc6b518245e1d8dbaab5c5/n8n-workflows/WF-Extraction.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
02_LLM_Pipeline v1.0. Uses executeWorkflowTrigger, httpRequest, seaTable. Event-driven trigger; 65 nodes.
This template is a powerful, reusable utility for managing stateful, long-running processes. It allows a main workflow to be paused indefinitely at "checkpoints" and then be resumed by external, async
Upload files from any source to your account Kommo or AmoCRM with a simple and reusable workflow. It can split a large file into small ones and upload chunks. Works for Kommo and amoCRM There are 3 re
Remixed Backup your workflows to GitHub from Solomon's work. Check out his templates.
Remixed Backup your workflows to GitHub from Solomon's work. Check out his templates.