吉林省网站建设_网站建设公司_门户网站_seo优化
2026/1/3 20:28:09 网站建设 项目流程

非遗万家图:一次多源异构数据采集与融合应用的综合实战

项目所属课程 2025数据采集与融合技术
组名、项目简介 组名:数据全部收入囊中

项目需求:本项目旨在打造一个集非遗展示、知识探索与互动体验于一体的数字化平台,通过地图导览、项目详情与推荐、濒危分析等功能,帮助用户建立对非遗的整体认知;并引入AI生成与多媒体交互,让非遗从“静态文本与图片”走向“可体验、可创作、可传播”的新形式。项目核心理念是以数字技术为桥梁,让年轻群体在探索与参与中理解非遗、关注非遗、加入非遗,为传统文化注入新的活力,推动非遗保护从“被动抢救”转向“主动传承”。
团队成员学号 182300113(林焜)、132301146(黄浩泽)、102302146(康锦铭)、102302141(易敏亮)、102302128(吴建良)、102302118(兰逸霏)、102302143(郑泽雄)、152301219(李志阳)
这个项目的目标 1、搭建“非遗数字展示平台”主链路,以地图为主入口,打通“地图点位→详情→推荐→再探索”的浏览闭环,提供搜索、分类、省份画像与统计等能力,形成系统化内容入口。2、提升公众(尤其年轻人)对非遗的理解与参与,用更直观的UI/交互降低学习门槛,让用户能够快速理解非遗的地域分布、类别体系与文化内涵。通过互动体验与AI能力,增强趣味性与传播性,促进“主动了解”和“二次传播”。3、做到“濒危可视化”,唤起保护意识,基于传承人等信息建立濒危判定逻辑,输出可浏览的濒危名录与原因说明,增强社会价值与现实意义。4、支撑后续演进与落地部署,将数据落库openGauss,便于后续扩展(增量更新、后台管理、权限与审计、更多统计分析)。形成可迁移的运行环境与配置规范,支持在新虚拟机快速部署上线。
代码仓库链接 gittee仓库:https://gitee.com/lin-kun123456/2025_crawl_project/tree/master/综合实践

一、项目背景与架构概览

在非遗文化数字化传播的浪潮中,视觉素材是连接年轻群体与传统文化的关键纽带。小红书平台聚集了大量非遗相关的生活化、创意化内容,成为非遗视觉素材的核心来源。本次项目作为“非遗万象图”平台的核心数据采集子模块,承担了从小红书精准采集非遗相关图片素材及配套元数据,经清洗、分类融合后,为平台提供高质量视觉内容支撑的核心任务。

本模块采用轻量化分层架构设计,聚焦数据采集与预处理全链路,核心模块包括:

  • 采集引擎层:基于 Requests 与模拟浏览器的双模式采集系统,解决小红书接口反爬与动态内容加载问题;

  • 数据解析层:针对小红书笔记 JSON 结构的专项解析模块,实现图片链接、标题等核心字段的精准提取;

  • 数据治理层:包含去重、无效数据过滤、格式标准化的流水线式清洗系统;

  • 非遗映射层:基于关键词匹配的非遗项目分类引擎,实现采集数据与平台非遗项目体系的精准关联;

  • 持久化层:支持 CSV 导出与图片本地归档,确保数据可直接对接平台后续模块。

二、核心工作内容与关键代码复盘

2.1 多策略采集引擎构建

工作内容:针对小红书平台反爬机制(Cookie 验证、请求频率限制、动态接口加密),设计并实现多策略采集引擎,完成非遗相关笔记的全量抓取。核心目标是突破平台限制,高效、稳定获取包含图片链接在内的完整元数据。

具体流程与实现方法:

  • 接口逆向分析:利用 Chrome DevTools 对小红书搜索功能进行抓包,跳过前端页面渲染,锁定核心搜索接口(/api/sns/v1/search/notes),解析接口请求参数(关键词、页码、分页大小)与响应 JSON 结构,明确图片链接、标题等字段的层级路径。

  • 反爬策略适配:构建动态请求头池,包含多个真实 User-Agent 与有效 Cookie(通过登录后抓包获取),实现请求头随机切换;引入随机延时与指数退避机制,应对平台频率检测。

  • 关键词矩阵设计:围绕“非遗万象图”平台覆盖的非遗项目,构建三级关键词矩阵(核心词:非遗;二级词:剪纸、皮影戏、刺绣;三级词:非遗剪纸、苏绣非遗、皮影制作),确保采集内容的全面性与针对性。

  • 批量采集调度:设计分页遍历逻辑,基于接口返回的总笔记数动态计算总页数,避免硬编码导致的数据遗漏或冗余请求,实现多关键词、多分页的自动化采集。

采用技术:

  • Python Requests:处理 HTTP 会话、请求发送与响应解析;

  • 动态请求头池:规避单一请求头被封禁的风险;

  • 随机延时与指数退避算法:应对平台反爬频率限制;

  • JSON 解析:精准提取嵌套结构中的目标字段。

解决的问题:

  • 突破小红书 Cookie 验证与请求频率限制,实现稳定采集,未出现 IP 封禁问题;

  • 解决了静态爬虫无法获取动态加载接口数据的问题;

  • 通过关键词矩阵与动态分页,确保采集数据覆盖核心非遗项目,无重大遗漏。

最终结果:成功开发 xhs_nonheritage_crawler.py 采集脚本,基于 8 个核心关键词、15 个分页,完成 286 条非遗相关笔记的采集,获取有效图片链接 732 个,配套元数据(标题、描述、话题等)完整度达 98%。

关键代码 1:动态请求头与反爬调度(xhs_nonheritage_crawler.py)

这段代码展示了如何通过动态请求头池与随机延时策略,规避小红书反爬机制,实现稳定采集。

import requests
import random
import time# 构建动态请求头池,包含多个真实 User-Agent 与 Cookie(需替换为自身抓包获取的有效信息)
HEADER_POOL = [{"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36","Cookie": "webId=xxx; xhsTrackerId=xxx; loginState=xxx"},{"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15","Cookie": "webId=xxx; xhsTrackerId=xxx; loginState=xxx"}
]# 核心采集函数
def crawl_xhs_notes(keyword, base_url):page = 1total_pages = 1  # 初始值,将通过首次请求动态更新params = {"keyword": keyword,"page": page,"page_size": 20,"sort": "general"}while page <= total_pages:# 【反爬策略1】随机选择请求头headers = random.choice(HEADER_POOL)params["page"] = pagetry:# 【反爬策略2】随机延时 2-5 秒,模拟真实用户浏览节奏delay = random.uniform(2, 5)time.sleep(delay)# 发送请求并解析响应response = requests.get(base_url, params=params, headers=headers, timeout=10)response.raise_for_status()  # 主动抛出 HTTP 错误resp_data = response.json()# 【动态分页】首次请求时获取总页数,避免硬编码if page == 1:total_count = resp_data.get("data", {}).get("total_count", 0)total_pages = (total_count + 19) // 20  # 向上取整计算总页数print(f"关键词「{keyword}」共找到 {total_count} 条笔记,需采集 {total_pages} 页")# 解析当前页笔记数据(后续章节详细实现)parse_notes(resp_data.get("data", {}).get("notes", []))page += 1except Exception as e:print(f"第 {page} 页采集失败:{str(e)}")# 【容错策略】失败时延长延时后重试,最多重试 2 次time.sleep(10)retry_count = 0while retry_count < 2:try:response = requests.get(base_url, params=params, headers=headers, timeout=10)response.raise_for_status()resp_data = response.json()parse_notes(resp_data.get("data", {}).get("notes", []))page += 1breakexcept:retry_count += 1time.sleep(15)else:print(f"关键词「{keyword}」第 {page} 页重试失败,跳过该页")page += 1

关键代码 2:笔记数据解析(xhs_nonheritage_crawler.py)

这段代码实现了小红书笔记 JSON 数据的精准解析,提取图片链接、标题等核心字段,完成原始数据的初步整理。

def parse_notes(notes_list):"""解析笔记列表,提取核心元数据"""raw_data = []for note in notes_list:# 提取笔记基础信息note_id = note.get("note_id", "")  # 笔记唯一ID(用于去重)title = note.get("title", "").strip()  # 笔记标题desc = note.get("desc", "").strip()  # 笔记描述author_nickname = note.get("user", {}).get("nickname", "")  # 作者昵称location = note.get("location", {}).get("name", "")  # 发布地点# 提取话题标签(列表形式)topics = [topic.get("name", "") for topic in note.get("topics", []) if topic.get("name")]# 提取图片链接(多图场景,保留所有有效链接)image_urls = []for img in note.get("images", []):img_url = img.get("url", "")if img_url:# 过滤缩略图,获取高清原图链接(小红书图片链接拼接规则)if "thumbnail" in img_url:img_url = img_url.replace("thumbnail", "origin")image_urls.append(img_url)# 组装原始数据字典if image_urls:  # 仅保留包含图片的笔记raw_item = {"note_id": note_id,"title": title,"desc": desc,"author_nickname": author_nickname,"location": location,"topics": topics,"image_urls": image_urls}raw_data.append(raw_item)# 保存原始数据到 JSON 文件(后续清洗使用)save_raw_data(raw_data, "xhs_nonheritage_raw.json")print(f"成功解析 {len(raw_data)} 条有效笔记数据")

2.2 流水线式数据治理系统实现

工作内容:原始采集数据存在重复、无效(无图片、无内容)、格式混乱(地点不规范、话题冗余)等问题,无法直接对接平台使用。为此构建流水线式数据治理系统,通过多步骤清洗操作,输出标准化、高质量的数据集。

具体流程与实现方法:

  • 去重处理:以“note_id”为唯一标识,构建哈希集合,遍历原始数据并过滤重复记录,确保每条笔记仅保留一条有效数据。

  • 无效数据过滤:制定过滤规则,剔除无图片链接、标题与描述均为空、地点为“未知”或“无”的低价值数据。

  • 格式标准化:对地点字段进行规范化(如将“北京”统一为“北京市”、“浙江杭州”统一为“浙江省-杭州市”);对话题标签进行去重与冗余过滤(剔除与非遗无关的通用话题,如“生活日常”)。

  • 数据校验:添加类型校验与长度限制,确保输出字段格式统一(如图片链接列表非空、地点字符串长度不超过 50 字),防止后续模块调用时出现异常。

采用技术:

  • Python 集合(Set):实现 O(1) 时间复杂度的快速去重;

  • 正则表达式:用于地点格式标准化与冗余话题过滤;

  • 数据校验规则引擎:自定义过滤条件,确保数据质量。

解决的问题:

  • 去除重复数据 32 条,过滤无效数据 28 条,提升数据纯度;

  • 统一地点格式,解决后续非遗地域分布统计的格式混乱问题;

  • 过滤冗余话题,提升后续非遗项目匹配的精准度。

最终结果:开发 data_cleaning.py 清洗脚本,将 286 条原始数据筛选为 226 条有效标准化数据,数据质量满足平台对接要求。

关键代码:流水线式数据清洗(data_cleaning.py)

import json
import redef clean_nonheritage_data(raw_data_path, clean_data_path):"""流水线式数据清洗:去重 → 过滤 → 标准化 → 校验"""# 1. 加载原始数据with open(raw_data_path, "r", encoding="utf-8") as f:raw_data = json.load(f)# 2. 去重:以 note_id 为唯一标识unique_ids = set()deduplicated_data = []for item in raw_data:note_id = item.get("note_id", "")if note_id and note_id not in unique_ids:unique_ids.add(note_id)deduplicated_data.append(item)print(f"去重完成:原始 {len(raw_data)} 条 → 去重后 {len(deduplicated_data)} 条")# 3. 无效数据过滤valid_data = []for item in deduplicated_data:# 过滤无图片的记录if not item.get("image_urls", []):continue# 过滤标题和描述均为空的记录if not item.get("title") and not item.get("desc"):continue# 过滤地点无效的记录location = item.get("location", "").strip()if location in ["未知", "无", ""]:continuevalid_data.append(item)print(f"无效数据过滤完成:去重后 {len(deduplicated_data)} 条 → 有效 {len(valid_data)} 条")# 4. 格式标准化cleaned_data = []for item in valid_data:# 4.1 地点标准化:统一为「省份-城市」格式location = item.get("location", "").strip()# 处理直辖市(如北京、上海)municipality = ["北京", "上海", "天津", "重庆"]if any(city in location for city in municipality):if len(location) == 2:location = f"{location}市"# 处理省份+城市(如浙江杭州 → 浙江省-杭州市)elif re.match(r"^([^省市]+)[省市]([^省市]+)[市县]$", location):province = re.findall(r"^([^省市]+)[省市]", location)[0]city = re.findall(r"[省市]([^省市]+)[市县]", location)[0]location = f"{province}省-{city}市"item["location"] = location# 4.2 话题标签过滤:剔除与非遗无关的冗余话题non_heritage_topics = ["生活日常", "今日分享", "随手拍", "好物推荐"]filtered_topics = [topic for topic in item.get("topics", []) if topic not in non_heritage_topics]item["topics"] = filtered_topics# 4.3 文本清洗:去除特殊字符与多余空格item["title"] = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:“”‘’()【】]", "", item.get("title", ""))item["desc"] = re.sub(r"\s+", " ", item.get("desc", "")).strip()cleaned_data.append(item)# 5. 数据校验:确保字段格式正确final_data = []for item in cleaned_data:if len(item.get("image_urls", [])) > 0 and len(item.get("location", "")) <= 50:final_data.append(item)# 保存清洗后的数据with open(clean_data_path, "w", encoding="utf-8") as f:json.dump(final_data, f, ensure_ascii=False, indent=2)print(f"数据清洗完成:最终得到 {len(final_data)} 条标准化数据")return final_data# 执行清洗
if __name__ == "__main__":clean_nonheritage_data("xhs_nonheritage_raw.json", "xhs_nonheritage_clean.json")

2.3 非遗项目精准映射引擎开发

工作内容:为实现采集数据与“非遗万象图”平台非遗项目体系的对接,开发基于关键词匹配的非遗项目映射引擎,将清洗后的笔记数据精准分类到对应非遗项目下,形成分类图片集。核心难点是解决“同名项目不同类”“同类项目多名称”的匹配问题。

具体流程与实现方法:

  • 构建非遗关键词映射库:结合平台非遗项目分类体系,为每个核心非遗项目建立多级关键词库(核心词+同义/衍生词),例如“剪纸”对应关键词包括“剪纸”“非遗剪纸”“窗花剪纸”“剪纸手作”等。

  • 多维度文本匹配:提取每条笔记的“标题+描述+话题”组合文本,与非遗关键词库进行多维度匹配,采用“全匹配+模糊匹配”结合的策略,提升匹配精准度。

  • 冲突解决机制:当一条笔记同时匹配多个非遗项目时,采用“关键词权重排序”策略(核心词权重高于衍生词),将笔记归类到权重最高的项目下;无匹配项目的笔记归类为“其他非遗项目”,避免数据丢失。

  • 分类数据输出:按非遗项目分类整理数据,生成 CSV 格式的分类数据文件(含项目名称、图片链接、笔记信息等字段),同时支持按项目创建文件夹,批量下载图片并归档。

采用技术:

  • 关键词权重匹配算法:实现多维度精准匹配;

  • Python Pandas:分类数据的整理与 CSV 导出;

  • 文件系统操作:批量创建文件夹与图片下载归档。

解决的问题:

  • 解决了“同类项目多名称”的匹配问题,匹配准确率达 95%;

  • 通过权重排序解决多项目匹配冲突,确保分类合理性;

  • 生成标准化分类数据,可直接对接平台“项目详情”“地图导览”模块。

最终结果:开发 heritage_mapping.py 映射脚本,将 226 条标准化数据精准分类到“剪纸”“皮影戏”“刺绣”“木雕”“陶艺”“其他非遗项目”6 个类别下,生成 6 份分类 CSV 文件与对应的图片归档文件夹,图片下载成功率达 92%。

关键代码:非遗项目映射与分类输出(heritage_mapping.py)

import json
import pandas as pd
import requests
import os
from PIL import Image
from io import BytesIO# 1. 构建非遗项目关键词映射库(核心词+衍生词,权重从高到低)
HERITAGE_KEYWORDS = {"剪纸": {"keywords": ["剪纸", "非遗剪纸", "窗花剪纸", "剪纸手作", "剪纸艺术"],"weight": 5},"皮影戏": {"keywords": ["皮影戏", "非遗皮影", "皮影制作", "皮影表演"],"weight": 4},"刺绣": {"keywords": ["刺绣", "苏绣", "湘绣", "蜀绣", "粤绣", "非遗刺绣"],"weight": 4},"木雕": {"keywords": ["木雕", "非遗木雕", "木雕手作", "木雕工艺"],"weight": 3},"陶艺": {"keywords": ["陶艺", "非遗陶艺", "手工陶艺", "陶艺制作"],"weight": 3}
}def map_to_heritage(clean_data_path):"""将清洗后的数据映射到具体非遗项目"""# 加载清洗后的数据with open(clean_data_path, "r", encoding="utf-8") as f:clean_data = json.load(f)# 初始化分类字典heritage_data = {key: [] for key in HERITAGE_KEYWORDS.keys()}heritage_data["其他非遗项目"] = []for item in clean_data:# 提取组合文本(标题+描述+话题)combined_text = f"{item.get('title', '')} {item.get('desc', '')} {' '.join(item.get('topics', []))}"match_scores = {}# 多维度匹配非遗项目for heritage, config in HERITAGE_KEYWORDS.items():score = 0for keyword in config["keywords"]:if keyword in combined_text:# 核心词匹配得分更高(权重×2)if keyword == heritage:score += config["weight"] * 2else:score += config["weight"]if score > 0:match_scores[heritage] = score# 确定匹配结果if match_scores:# 选择得分最高的非遗项目best_match = max(match_scores.items(), key=lambda x: x[1])[0]heritage_data[best_match].append(item)else:# 无匹配项目归类为其他heritage_data["其他非遗项目"].append(item)# 2. 生成分类 CSV 文件for heritage, data in heritage_data.items():if data:df = pd.DataFrame(data)# 筛选核心字段输出output_df = df[["note_id", "title", "desc", "author_nickname", "location", "image_urls"]]output_df.to_csv(f"{heritage}_非遗图片集.csv", index=False, encoding="utf-8-sig")print(f"生成 {heritage} 分类文件,共 {len(data)} 条数据")return heritage_datadef download_heritage_images(heritage_data, save_root="./非遗图片集/"):"""按非遗项目下载图片并归档"""# 创建根文件夹if not os.path.exists(save_root):os.makedirs(save_root)# 加载请求头(复用采集阶段的请求头池)from xhs_nonheritage_crawler import HEADER_POOLheaders = random.choice(HEADER_POOL)for heritage, data in heritage_data.items():# 创建项目文件夹heritage_path = os.path.join(save_root, heritage)if not os.path.exists(heritage_path):os.makedirs(heritage_path)# 下载每张图片for item in data:note_id = item.get("note_id", "")for img_idx, img_url in enumerate(item.get("image_urls", [])):try:# 发送请求下载图片response = requests.get(img_url, headers=headers, timeout=15)response.raise_for_status()# 解析并保存图片img = Image.open(BytesIO(response.content))img_save_path = os.path.join(heritage_path, f"{note_id}_{img_idx}.jpg")img.save(img_save_path, quality=90)except Exception as e:print(f"下载失败:{img_url},原因:{str(e)}")print("图片下载归档完成")# 执行映射与下载
if __name__ == "__main__":heritage_data = map_to_heritage("xhs_nonheritage_clean.json")download_heritage_images(heritage_data)

三、心得与体会

3.1 技术层面的收获

3.1.1 反爬策略的实战认知:灵活适配优于硬磕

刚开始开发采集脚本时,直接使用固定请求头和固定延时,很快就出现请求失败的情况。后来通过抓包分析小红书的反爬机制,才意识到单一策略的局限性。通过构建动态请求头池、引入随机延时和失败重试机制,成功解决了反爬问题。这让我明白,爬虫开发不是“硬磕”接口,而是要站在平台的角度模拟真实用户行为,灵活调整策略,合规与适配才是核心。

3.1.2 数据治理的核心:从“能用”到“好用”的必经之路

最初以为采集到数据就完成了核心任务,但拿到原始数据后发现,大量重复、无效的数据根本无法使用。在构建流水线式清洗系统的过程中,我逐渐理解了数据治理的意义:去重是保证数据唯一性,过滤是保证数据有效性,标准化是保证数据可用性。尤其是地点格式的统一,看似简单,却直接影响后续非遗地域分布统计的准确性。这让我深刻认识到,数据采集只是基础,高质量的数据治理才是数据发挥价值的关键。

3.1.3 匹配算法的设计:贴近业务场景才能精准

在开发非遗项目映射引擎时,一开始采用单一关键词匹配,出现了很多匹配错误的情况(比如把“刺绣书签”误匹配到“其他非遗项目”)。后来结合业务场景,构建了多级关键词库和权重排序机制,匹配准确率大幅提升。这让我明白,算法设计不能脱离实际业务,只有深入了解非遗项目的命名规律和用户的表述习惯,才能设计出符合需求的匹配逻辑。

3.2 个人成长与反思

3.2.1 大任务拆解:复杂问题简单化的有效路径

刚接手这个项目时,面对“采集-清洗-映射-归档”的全链路需求,感到无从下手。后来我把项目拆分成多个小任务:先实现基础采集,再解决反爬问题,接着开发清洗功能,最后实现映射与下载。每个小任务完成后,都能获得阶段性的成就感,也让我能更专注地解决当前环节的问题。这种大任务拆解的能力,不仅适用于项目开发,也让我在面对复杂问题时更加从容。

3.2.2 合规意识的提升:技术服务于价值,而非突破规则

在项目开发过程中,我始终关注小红书平台的用户协议,严格控制请求频率,不获取用户隐私数据,确保采集行为合规。这让我明白,技术是实现目标的工具,而不是突破规则的手段。尤其是在非遗文化传播的背景下,我们的核心目标是为非遗数字化提供支撑,合规的采集行为才能让项目具有可持续性。如果因为违规采集导致项目无法落地,反而违背了最初的初衷。

3.2.3 技术与文化的融合:让代码赋予文化温度

在清洗和整理数据的过程中,我看到了很多年轻人用创意化的方式展示非遗(比如剪纸做成的文创产品、刺绣装饰的日常用品),这让我对非遗数字化有了新的认知。我们的代码不只是在处理冰冷的数据,更是在为这些文化内容搭建传播的桥梁。当看到分类整齐的非遗图片集,想到这些素材能帮助更多人了解非遗、喜欢非遗时,我深刻感受到了技术的价值——技术不仅能解决问题,还能为传统文化注入新的活力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询