Chord - Ink Shadow 项目实战利用爬虫构建艺术风格训练数据集最近在做一个挺有意思的项目叫 Chord - Ink Shadow目标是训练一个能生成特定水墨艺术风格的模型。想法很美好但第一步就卡住了上哪儿去找那么多高质量、风格统一的水墨画数据呢公开的数据集要么风格太杂要么数量不够完全没法用。没办法只能自己动手丰衣足食了。我琢磨着既然网上有那么多艺术网站和画廊上面有海量的高清作品为什么不自己写个爬虫把它们“请”下来呢这听起来像是个大工程但实际做下来发现只要思路清晰用 Python 一步步来并没有想象中那么复杂。今天我就把这个从零开始构建专属艺术数据集的完整过程分享给你如果你也想为自己的 AI 项目准备点“独家食材”这篇实战指南应该能帮上忙。1. 为什么需要自己构建数据集你可能想问现在开源数据集那么多为什么还要费劲自己爬这事儿我一开始也纠结过但实际对比后发现自己动手有几个无法替代的好处。首先是风格纯度问题。像 Chord - Ink Shadow 这种项目对艺术风格的统一性要求极高。我需要的是那种笔触飘逸、墨色浓淡有致、构图留白讲究的东方水墨画而不是泛指所有“黑白画”或“中国画”。通用数据集里往往鱼龙混杂古典工笔、现代重彩、甚至书法都可能混在一起直接用的话模型学出来的风格会不伦不类。其次是数据质量与版权。很多公开数据集里的图片分辨率低还有水印这直接影响了后续模型训练的效果。更重要的是用于商业或研究的数据版权必须清晰。通过爬虫从明确允许下载或遵循合理使用原则的公开艺术网站获取资源我们能更好地把控数据的来源合法性为项目扫清潜在风险。最后是数据的针对性与扩展性。自己构建数据集意味着你可以完全控制数据的构成。比如我可以专门收集某位大师如齐白石、徐悲鸿某个时期的作品聚焦于“花鸟”或“山水”单一题材让模型学习的特征更集中。未来如果想把风格扩展到“敦煌壁画”或“浮世绘”这套数据采集和处理的流程也能快速复用非常灵活。所以自己构建数据集虽然前期投入时间多但它带来的风格精准度、质量可控性和项目适配性是通用数据集无法比拟的。这就像做一道精致的菜市场买的预制菜固然方便但要想做出独特的风味还得从挑选和处理原始食材开始。2. 项目规划与目标网站分析动手写代码之前清晰的规划能省去后面一大堆麻烦。我的核心目标是构建一个用于水墨画风格生成的、高质量、标注清晰的图像数据集。我定了这么几个具体目标规模初期目标收集 5000-10000 张高质量水墨画图像。质量图像分辨率不低于 1024x1024 像素格式为 JPG 或 PNG无肉眼可见的压缩伪影或水印。标注每张图像需要包含基本的元数据如画家、作品名称、创作年代如果可得、题材分类山水、人物、花鸟等。结构数据要按画家、题材等维度组织好文件夹方便后续管理。接下来就是找“粮仓”了。经过一番搜寻和评估我锁定了几个优质的公开艺术资源网站博物馆与美术馆官网许多大型博物馆例如大都会艺术博物馆、故宫博物院都提供了公开的数字藏品库图片质量极高且版权信息明确通常可用于教育和研究。专业艺术图库网站一些专注于艺术分享的网站汇集了大量艺术家上传的作品。需要仔细阅读网站的robots.txt文件和使用条款确保爬取行为在其允许范围内。学术机构数据库部分大学或研究机构的艺术史项目会公开一些专题数据集虽然规模可能不大但标注非常专业。这里有一个至关重要的步骤法律与道德审查。在选定目标网站后我做了三件事仔细阅读网站的Terms of Service或Usage Guidelines明确是否禁止爬虫以及数据的使用限制。检查robots.txt文件通常在网站根目录如https://example.com/robots.txt尊重其中关于爬取频率和禁止爬取目录的规定。规划礼貌的爬取策略设置较长的请求间隔如 2-5 秒模拟人类浏览行为避免对目标网站服务器造成压力。我们这次实战就以一个假设的、结构清晰的公开艺术图库网站为例来演示整个流程。真实操作时请务必替换成你找到的、合规的真实网站地址。3. 爬虫实战从网页到图片万事俱备开始写代码。我选择用 Python主要是因为相关的库太丰富了用起来顺手。3.1 环境搭建与工具选择首先创建一个干净的 Python 环境用venv或conda都行然后安装我们需要的核心武器pip install requests beautifulsoup4 lxml pandas pillow简单介绍一下这几个库requests用来发送 HTTP 请求从网站获取网页源代码。它比 Python 自带的urllib更简单易用。beautifulsoup4配合lxml这是网页解析的“黄金搭档”。BeautifulSoup能帮我们把杂乱无章的 HTML 代码解析成一棵结构清晰的树然后像查字典一样轻松地找到图片链接、标题等我们需要的信息。lxml是一个解析器速度快效率高。pandas数据处理神器。爬下来的图片信息如URL、标题、画家等可以先用它来整理和清洗非常方便。Pillow(PIL)Python 的图像处理库。下载图片后可以用它来检查图片尺寸、格式甚至进行简单的裁剪或缩放。3.2 分析网页结构与制定爬取策略打开目标网站的页面比如一个展示水墨画列表的页面。按 F12 打开开发者工具使用“检查元素”功能。我们需要找到两个关键模式翻页规律列表页的 URL 规律。比如第一页是https://example.com/ink-paintings?page1第二页是?page2。图片链接与元数据位置在列表页中找到每个作品缩略图对应的详情页链接。然后进入详情页找到高清大图的真实地址通常是img标签的src属性以及作品名称、画家等文本信息所在的 HTML 标签。假设我们分析后发现列表页上每个作品块都有一个class为artwork-item的div里面的a标签链接到详情页。详情页里高清大图在img标签且id为main-image作品标题在h1标签里画家信息在一个class为artist-name的span里。基于这个分析我们的爬取策略就清晰了第一层爬取循环遍历列表页获取所有作品的详情页链接。第二层爬取逐个访问详情页提取高清图片 URL 和元数据。持久化存储将元数据保存到 CSV 文件同时将图片文件下载到本地按画家或题材分类存放。3.3 编写核心爬虫代码下面是一个高度简化的核心代码框架展示了如何实现上述策略。请注意在实际使用中你需要根据目标网站的实际 HTML 结构修改选择器如class、id并添加更完善的错误处理。import os import time import requests from bs4 import BeautifulSoup import pandas as pd from urllib.parse import urljoin # 配置 BASE_URL https://example.com/ink-paintings DOWNLOAD_DIR ./ink_painting_dataset os.makedirs(DOWNLOAD_DIR, exist_okTrue) HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } # 存储元数据的列表 metadata_list [] def fetch_page(url): 获取页面内容并做基本错误处理 try: resp requests.get(url, headersHEADERS, timeout10) resp.raise_for_status() # 如果状态码不是200抛出异常 # 简单检查是否为HTML页面 if text/html in resp.headers.get(Content-Type, ): return resp.text else: print(f警告: {url} 返回的内容不是HTML) return None except requests.RequestException as e: print(f请求 {url} 时出错: {e}) return None def parse_list_page(html): 解析列表页提取所有详情页链接 soup BeautifulSoup(html, lxml) artwork_links [] # 根据实际网站结构修改选择器 for item in soup.select(div.artwork-item a): link item.get(href) if link: full_url urljoin(BASE_URL, link) artwork_links.append(full_url) return artwork_links def parse_detail_page(html, detail_url): 解析详情页提取图片URL和元数据 soup BeautifulSoup(html, lxml) metadata {detail_url: detail_url} # 提取高清图片URL - 根据实际结构修改 img_tag soup.find(img, idmain-image) if img_tag and img_tag.get(src): metadata[image_url] urljoin(detail_url, img_tag[src]) else: metadata[image_url] None # 提取作品标题 - 根据实际结构修改 title_tag soup.find(h1) metadata[title] title_tag.get_text(stripTrue) if title_tag else Unknown # 提取画家信息 - 根据实际结构修改 artist_tag soup.find(span, class_artist-name) metadata[artist] artist_tag.get_text(stripTrue) if artist_tag else Unknown # 可以继续提取年代、题材等信息... # metadata[era] ... # metadata[category] ... return metadata def download_image(img_url, save_path): 下载图片到本地 if not img_url: return False try: resp requests.get(img_url, headersHEADERS, streamTrue, timeout30) if resp.status_code 200: with open(save_path, wb) as f: for chunk in resp.iter_content(1024): f.write(chunk) return True except Exception as e: print(f下载图片失败 {img_url}: {e}) return False def main(): all_artwork_links [] # 第一步爬取所有列表页收集详情页链接 print(开始爬取列表页...) for page in range(1, 6): # 假设爬取前5页 list_url f{BASE_URL}?page{page} print(f处理列表页: {list_url}) html fetch_page(list_url) if html: links parse_list_page(html) all_artwork_links.extend(links) print(f 找到 {len(links)} 个作品链接) time.sleep(2) # 礼貌延迟避免请求过快 # 第二步遍历详情页下载图片和元数据 print(f\n开始处理 {len(all_artwork_links)} 个详情页...) for idx, detail_url in enumerate(all_artwork_links): print(f处理 [{idx1}/{len(all_artwork_links)}]: {detail_url}) html fetch_page(detail_url) if not html: continue metadata parse_detail_page(html, detail_url) # 下载图片 if metadata.get(image_url): # 用画家和作品名生成文件名避免重复和特殊字符 artist_dir os.path.join(DOWNLOAD_DIR, metadata[artist].replace(/, _)) os.makedirs(artist_dir, exist_okTrue) # 简单生成文件名实际可更复杂 filename f{metadata[title][:50].replace(/, _)}.jpg save_path os.path.join(artist_dir, filename) if download_image(metadata[image_url], save_path): metadata[local_path] save_path print(f 图片已保存至: {save_path}) else: metadata[local_path] None print(f 图片下载失败) else: metadata[local_path] None metadata_list.append(metadata) time.sleep(1) # 详情页请求也加入延迟 # 第三步保存元数据到CSV df pd.DataFrame(metadata_list) csv_path os.path.join(DOWNLOAD_DIR, metadata.csv) df.to_csv(csv_path, indexFalse, encodingutf-8-sig) print(f\n元数据已保存至: {csv_path}) print(f总计处理 {len(metadata_list)} 个作品。) if __name__ __main__: main()这段代码提供了一个完整的骨架。你需要根据目标网站的具体情况调整parse_list_page和parse_detail_page函数中的选择器。运行后你会得到一个按画家分好类的图片文件夹以及一个记录了所有信息的metadata.csv文件。4. 数据清洗与预处理爬下来的数据是“生”的直接喂给模型可能会吃坏肚子。所以清洗和预处理这一步必不可少。1. 去重与无效数据过滤去重检查metadata.csv根据图片URL或下载后的文件MD5值删除完全重复的作品。过滤删除image_url为空或local_path为空的记录即下载失败的。检查文件大小剔除那些明显过小可能只是缩略图或损坏文件的图片。2. 图像质量筛选与标准化分辨率检查用Pillow库打开图片检查其尺寸。对于水墨画风格训练我设定了最低 512x512 像素的门槛目标是保留 1024x1024 以上的图片。from PIL import Image import os def check_image_resolution(image_path, min_width512, min_height512): try: with Image.open(image_path) as img: width, height img.size return width min_width and height min_height except Exception as e: print(f无法打开图片 {image_path}: {e}) return False格式统一将非 JPG/PNG 的图片转换格式或者统一转换为 PNG 以保留更多细节但文件会更大。简单清洗可以尝试用Pillow进行自动的对比度增强、去噪等操作但要非常谨慎避免改变原画的艺术风格。这一步通常不是必须的。3. 元数据整理与增强缺失值处理对于画家、标题等缺失的信息可以尝试设为“Unknown”或者根据文件夹名、文件名进行推断。分类标签如果元数据中没有题材分类你可能需要手动或借助另一个简单的图像分类模型或CLIP模型对图片进行打标比如分为“山水”、“花鸟”、“人物”等。这能为后续的精细化训练提供便利。数据划分将处理好的数据划分为训练集、验证集和测试集例如 80%, 10%, 10%并相应地更新metadata.csv或创建单独的索引文件。经过这些步骤你得到的就不再是一堆杂乱的文件而是一个结构清晰、质量可控、标注明确的标准化数据集了。5. 总结与后续步骤走完这一整套流程一个为 Chord - Ink Shadow 量身定制的艺术风格数据集就初步建成了。回过头看最花时间的其实不是写爬虫代码而是前期的网站寻找、结构分析和合规性检查。代码本身一旦跑通剩下的就是等待和简单的后期处理。这个数据集的价值立刻就能体现出来。相比于使用混杂的公开数据集用这个纯净、风格一致的数据集去微调模型比如 Stable Diffusion 的 Lora效果提升会非常明显。模型能更快地捕捉到水墨画中特有的笔法、墨韵和留白意境生成的作品风格会更纯粹、更“有那味儿”。当然这只是一个开始。有了这套方法论你可以轻松地复用到其他艺术风格的收集上比如油画、素描、版画等等。爬虫脚本稍作修改就能适应不同的网站结构。数据清洗和标注的流程更是可以直接复用。在实际操作中你可能会遇到反爬机制更复杂的网站可能需要用到Selenium这样的浏览器自动化工具或者需要处理动态加载的内容。也可能需要设计更智能的元数据提取方法。但核心思路是不变的分析目标、规划路径、编写工具、处理结果。最后再强调一次在整个过程中请务必保持对目标网站的尊重遵守robots.txt控制请求频率仅将数据用于合法合规的研究与学习目的。好的技术应该用在创造价值的地方构建数据集只是我们创作之旅的第一步希望你的 Chord - Ink Shadow 项目能因此诞生出惊艳的作品。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。