小红书数据采集实战:Python爬虫与反爬绕过全攻略 简介本资源是一套完整可用的小红书平台Python爬虫源码面向计算机专业本科生及入门级爬虫开发者适用于毕业设计、课程实践与数据采集技术学习。项目包含1080个文件以781个JavaScript文件支撑前端交互与自动化逻辑、68个TypeScript文件增强类型安全、54个Markdown文档含README说明与使用指南及10个核心Python脚本如search.py、home.py、profile.py等为主干辅以JSON配置、工具类模块xhs_utils与POJO模型定义结构清晰、模块解耦便于理解爬虫架构与二次开发。压缩包仅2.55MB轻量易部署。目前已有1824人学习下载提供开箱即用的搜索、首页抓取、用户主页与单帖详情解析能力并内置.gitignore、.env等工程化配置兼顾可维护性与合规提醒。1. 写在前面这项目到底是什么适合谁先别急着往下翻代码我得先给这个标题泼一盆冷水醒醒脑。你在闲鱼、GitHub、各种源码站上看到“小红书爬虫源码Python编写下载即可运行”大概率会踩坑要么是阉割版要么是带后门的要么干脆就是个空壳子收智商税。但话又说回来这个小项目本身确实是个好东西尤其是对两类人价值极高一类是正在愁毕业设计选题的计算机专业学生另一类是刚学完Python基础、想找个综合实战项目练手的新手。为什么说它适合做毕业设计因为小红书爬虫这个课题“麻雀虽小五脏俱全”。它涵盖了网络请求、数据解析、动态渲染处理、验证码识别、数据存储、反爬对抗、异步并发甚至还能扯上数据分析和用户画像。你可以把它包装成“基于Python的小红书用户行为数据采集与分析系统”这个题目一写上去答辩老师一看就知道你做了实际工作不是那种随便找个管理系统糊弄的。那这东西到底能干什么核心功能就三件事第一按关键词搜索笔记采集笔记的标题、正文、点赞数、收藏数、评论数、作者信息第二按用户主页采集某个博主的全部笔记列表和详情第三批量下载笔记配图或视频。所有数据最终落到Excel或数据库里方便后续分析。我要先立个规矩本文只讲技术原理和学习用途所有代码都拿公开账号的公开数据做演示采集频率严格控制。你要是拿它去刷接口、爬隐私、搞商业竞争出了事自己兜着跟我没关系。合规红线我心里有数希望你也有。2. 技术选型为什么是Python为什么这么选做爬虫的技术栈选择其实挺多的Node.js、Go、Java都能干但Python在这个领域几乎是无脑首选。原因很简单生态太成熟了你需要的每一个功能几乎都有现成库不需要从零造轮子。需求Python库替代方案对比发送HTTP请求requests比urllib简洁太多比httpx成熟稳定动态页面渲染Selenium / PlaywrightSelenium老牌稳定Playwright更现代但学习成本略高数据解析BeautifulSoup4 lxml正则表达式太脆弱scrapy的Selector学习曲线陡验证码识别ddddocr免费开源比接第三方打码平台省钱数据存储pandas openpyxl直接操作Excel最简单适合毕设展示异步加速aiohttp比requests快一个量级但维护成本高针对小红书这个目标有几个特殊情况需要考虑。第一小红书是重度的动态渲染网站几乎所有数据都是通过XHR接口异步加载的直接requests拿HTML源码只能拿到一个空壳框架。这时候有两条路一条是用Selenium模拟浏览器操作让浏览器自己渲染然后从浏览器里取数据另一条是直接找它的后端接口模拟请求参数。我们最终选择的是以接口为主、Selenium为辅的混合方案。原因后面细说。第二小红书的签名机制是重头戏。熟悉的人都知道它的接口有个x-s、x-t这样的签名参数是JS逆向的产物。早期很多教程教你用node.js执行JS代码来生成签名现在这套玩法的成本越来越高因为字节的前端工程师一直在升级混淆方案。我的方案很简单粗暴不逆向了直接用Selenium的浏览器环境让页面自己把数据加载出来然后从加载完的DOM或接口响应里截数据。虽然慢一点但稳定适合入门学习也适合毕设这种不追求极致吞吐量的场景。第三登录态管理。小红书的游客态接口能请求到的数据非常有限很多接口要求登录。毕设项目大概率需要模拟登录但密码登录要过滑块验证那个性价比太低了。我采用的是扫码登录方案用Python调用摄像头或者读取本地二维码截图然后轮询登录状态拿到cookie之后存下来复用。这套方案代码量不大但体验很好用户完全不感知“反爬”的压力。3. 没跑起来的都说坑环境准备与依赖安装标题说“下载即可运行”我听到就笑了。说实话Python项目没有“下载即运行”这回事至少你得先把环境弄好。我见过太多人卡在环境这关项目下载了三天运行报错了一周。这里我把磨出来的步骤完整走一遍避免你浪费大把时间。3.1 Python版本和虚拟环境Python要用3.8到3.10别用3.11以上为什么因为部分依赖包如tensorflow、scrapy的老版本在3.11上编译不过虽然我们的项目不用tensorflow但ddddocr的onnxruntime依赖在3.11上有坑。省心起见3.9是黄金版本。虚拟环境必须建别嫌麻烦不是因为你洁癖而是因为爬虫项目依赖版本极其敏感requests升级到2.31之后某些接口行为会变化Selenium升级到4.x之后定位元素的语法和3.x不一样你装了一堆其他项目很有可能把版本搞乱到时候排查依赖冲突的时间比写代码的时间还长。python -m venv xhs_env # Windows下激活 xhs_env\Scripts\activate # macOS/Linux下激活 source xhs_env/bin/activate激活之后再用pip安装依赖。3.2 核心依赖安装与验证依赖文件直接给出来不用一个个手敲pip install requests2.31.0 pip install beautifulsoup44.12.2 pip install lxml4.9.3 pip install selenium4.15.0 pip install ddddocr1.4.7 pip install pandas2.0.3 pip install openpyxl3.1.2 pip install retrying1.3.4 pip install python-dotenv1.0.0版本是我验证过的稳定组合闭着眼睛装不会出大问题。但是有两个容易踩坑的点要提前打预防针。第一Selenium必须要配一个浏览器驱动driver。我们选择了Chrome系因为它的生态最全。Chrome的版本和chromedriver的版本必须严格匹配装错了启动的时候直接报SessionNotCreatedException。这里说个技巧用Chrome 115以上的版本可以不用手动下载chromedriver直接用Selenium Manager自动管理驱动但需要保持网络畅通。如果是国内网络环境推荐手动下载放到项目目录并指定路径。第二ddddocr在首次运行时会自动下载一个模型文件如果下载失败它会报一个看似莫名其妙的错误。解决办法是手动到它的GitHub仓库下载模型文件放到用户目录下的.ddddocr文件夹里。这也是很多新手说“代码没毛病但就是跑不起来”的第二大原因。装完之后用一行代码验证环境import requests, bs4, selenium, ddddocr, pandas print(环境OK)能打印出环境OK再往下走。3.3 项目目录结构一个清晰的目录结构能让你后期维护和写毕业论文的时候省很多事参考我的布局xhs_spider/ ├── main.py # 主入口 ├── config.py # 配置文件 ├── requirements.txt # 依赖清单 ├── spider/ │ ├── __init__.py │ ├── client.py # 请求客户端封装 │ ├── login.py # 登录模块 │ ├── signature.py # 签名处理模块 │ ├── parser.py # 数据解析模块 │ └── downloader.py # 图片/视频下载模块 ├── utils/ │ ├── __init__.py │ ├── cookie_manager.py # Cookie管理 │ └── logger.py # 日志模块 ├── data/ │ ├── notes.xlsx # 导出数据 │ └── images/ # 下载的图片 └── logs/ └── run.log # 运行日志这套结构其实就是一个低配版的Scrapy架构把请求、解析、存储、工具拆开好处是每个模块独立测试出了bug不用满文件找。毕业论文里还能配上架构图显得很专业。4. 核心机制拆解登录、签名和数据解析的底层逻辑这一节是整个项目最硬核的部分也是你为什么能过答辩、能学到真东西的地方。我把三个核心机制掰开揉碎讲清楚。4.1 登录态没有cookie什么都白搭小红书的平台策略是“未登录可以看但看不多”。游客态能请求首页推荐流但搜索接口基本只能返回个位数结果而且很快会触发验证码。要批量采集必须先登录。登录不能选择账号密码为什么因为密码登录之后大概率触发滑块验证那个滑块已经不是简单的拖动拼图了现在是有轨迹检测和缺口识别双重校验的。用Selenium模拟拖动的成功率很低而且封号风险大。扫码登录就安全很多——本质上就是你自己拿手机扫一下平台认为是人工在操作风控概率大大降低。扫码登录的核心逻辑from selenium import webdriver from selenium.webdriver.common.by import By import time, qrcode def qr_login(driver): driver.get(https://www.xiaohongshu.com) time.sleep(3) # 找到登录入口并点击 login_btn driver.find_element(By.CSS_SELECTOR, button.login-btn) login_btn.click() time.sleep(2) # 切换到扫码登录tab qr_tab driver.find_element(By.CSS_SELECTOR, div.tab-login div:nth-child(2)) qr_tab.click() time.sleep(2) # 截取二维码 qr_img driver.find_element(By.CSS_SELECTOR, div.qr-code img) qr_img.screenshot(data/qr.png) # 这里可以用 qrcode 库识别或直接用摄像头扫屏幕 # 轮询等待登录成功 for _ in range(120): time.sleep(1) if login not in driver.current_url: # 登录成功保存cookies import json cookies driver.get_cookies() with open(data/cookies.json, w) as f: json.dump(cookies, f) print(登录成功cookie已保存) return True return False这个代码有两个细节值得说。一是二维码截图的时机一定要等二维码图片加载完成否则截到的是一张白图识别不出内容。我的做法是加个显式等待轮询二维码的src属性不为空截图之前最好加个1秒的缓冲让图片彻底渲染。二是登录成功的判断不要只看URL变化有些情况下登录弹窗关了但没登录成功更准确的方法是尝试请求一个需要登录的接口看返回的JSON里有没有用户信息。4.2 签名机制不逆向也能绕过去的方案小红书大部分接口都要带x-s、x-t这个签名参数早期方案是找到某个JS文件里的加密函数用Python或者Node.js去执行它。但平台现在把签名逻辑拆分到多个JS文件里各种混淆和动态加载维护成本极高今天能用明天可能就挂了。所以我的思路是换个角度既然签名最终是浏览器里算出来的那我直接在浏览器里取数据不就行了吗具体操作方式是Selenium打开目标页面等数据渲染完成后直接从页面里取数据。比如搜索页搜索结果会渲染成一堆卡片节点我从节点里提取信息即可。这种方式完全绕开了签名校验因为Selenium本身就是真实浏览器它发出的所有请求都自带合法签名。这里有个取舍要讲清楚Selenium方式最大的缺点是慢——每翻一页要等页面加载网络快也得一两秒慢的话三五秒并且需要跑一个真实的浏览器窗口内存占用大。但它有一个无法替代的优点稳定你不需要关心前端工程师什么时候改签名算法。对于毕设和个人学习稳定比速度重要得多。如果确实想要更高效的方案可以走混合路线先用Selenium登录拿到cookie然后用requests直接请求接口同时把一个有效的签名通过Selenium调页面JavaScript获取。具体来说def get_signature(driver, url): script return window._webmsxyw.sign(url); return driver.execute_script(script)这是从页面上下文中直接调签名函数这样requests也能发出带合法签名的请求。这个方法介于纯逆向和纯Selenium之间是个不错的进阶技巧。但不建议新手一上来就搞这个先跑通Selenium方案理解了整体逻辑以后再去过渡到混合方案会更顺畅。4.3 数据解析从HTML到结构化数据的完整过程Selenium拿到的是浏览器渲染后的完整DOM但如何从这些DOM节点里找到笔记数据这里有一套稳定的套路。红书搜索页每篇笔记卡片的结构比较稳定核心信息都在section classnote-item这个节点里。定位到节点后通过CSS选择器提取def parse_search_result(driver): cards driver.find_elements(By.CSS_SELECTOR, section.note-item) data [] for card in cards: try: title card.find_element(By.CSS_SELECTOR, a.title).text link card.find_element(By.CSS_SELECTOR, a.title).get_attribute(href) author card.find_element(By.CSS_SELECTOR, span.author).text likes card.find_element(By.CSS_SELECTOR, span.like-wrapper).text data.append({ 标题: title, 链接: link, 作者: author, 点赞数: likes, 采集时间: datetime.now().strftime(%Y-%m-%d %H:%M:%S) }) except Exception as e: logger.warning(f解析卡片失败: {e}, 原始HTML: {card.get_attribute(outerHTML)[:200]}) continue return data这里有个大坑需要特别说明。小红书的页面是无限滚动的你直接往下翻数据会不断地加载但DOM里的节点会越来越多导致浏览器越来越卡。处理方式是“分段加载”每滚一屏把当前页面的数据全部取走然后清空DOM通过重置子节点的方式再继续滚动。这个技巧能防止内存爆炸实测下来跑几千条数据不会卡。另一个细节是点赞数的格式问题小红书显示的是“1.2万”这种格式直接存进Excel后期做数据分析很不方便。我的处理是写一个格式化函数把带“万”的换算成数字把“赞”也去掉统一成整数类型方便后续排序和统计。至于图片和视频的下载用requests流式下载def download_media(url, filename): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.xiaohongshu.com/ } r requests.get(url, headersheaders, streamTrue, timeout10) if r.status_code 200: with open(filename, wb) as f: for chunk in r.iter_content(chunk_size8192): f.write(chunk) print(f下载完成: {filename}) else: print(f下载失败: {url}, 状态码: {r.status_code})注意Referer一定不能丢这是小红书图片和视频防盗链机制的关键校验。丢了Referer返回的十有八九是403。5. 完整实操30分钟跑通一个搜索采集流程现在到了保姆级实操环节。我按时间线把从零到有、从配置文件到代码运行的完整过程走一遍你可以边读边跟着敲30分钟能跑通第一版。5.1 第一步写配置文件集中管理关键参数我把所有可变的配置集中到config.py里这样不同场景切换只需改一个文件不用全局找参数import os from dotenv import load_dotenv load_dotenv() # 搜索关键词可以配置多个用逗号分隔 KEYWORD os.getenv(KEYWORD, 美食) # 需要采集的笔记数量 MAX_NOTES int(os.getenv(MAX_NOTES, 50)) # Chrome驱动路径如果是Selenium Manager自动管理可以不填 CHROME_DRIVER_PATH os.getenv(CHROME_DRIVER_PATH, ) # 账号相关 COOKIE_FILE data/cookies.json # 输出文件 OUTPUT_EXCEL data/notes.xlsx # 请求间隔秒控制在合理范围避免触发风控 REQUEST_INTERVAL float(os.getenv(REQUEST_INTERVAL, 2))注意环境变量这种方式好处是参数不被硬编码在代码里将来发到GitHub上也不用担心泄露敏感信息。你可以创建一个.env文件来存放这些配置。5.2 第二步初始化浏览器和登录状态这步的难点在于复用Cookie避免每次运行都要扫码。写一个cookie管理器import json, os from selenium import webdriver def load_cookies(driver, cookie_file): if not os.path.exists(cookie_file): print(未找到Cookie文件开始扫码登录...) qr_login(driver) return with open(cookie_file, r) as f: cookies json.load(f) driver.get(https://www.xiaohongshu.com) time.sleep(2) for cookie in cookies: driver.add_cookie(cookie) time.sleep(2) driver.refresh() print(Cookie加载完成)Cookie的过期问题不用特别担心小红书网页端的cookie有效期通常在7天以上过期了再扫码一次就行。我建议在Cookie保存时间超过3天之后程序弹个提示提醒用户“cookie可能过期如果请求异常请重新登录”。5.3 第三步搜索采集主流程def search_and_collect(keyword, max_notes): driver init_driver() load_cookies(driver, COOKIE_FILE) search_url fhttps://www.xiaohongshu.com/search_result?keyword{keyword} driver.get(search_url) time.sleep(3) results [] scroll_count 0 no_new_data_count 0 while len(results) max_notes: # 解析当前页数据 page_data parse_search_result(driver) if not page_data: no_new_data_count 1 if no_new_data_count 3: print(连续3次无新数据退出采集) break else: no_new_data_count 0 # 去重合并 existing_ids {item[链接] for item in results} new_items [item for item in page_data if item[链接] not in existing_ids] results.extend(new_items) # 滚动页面触发加载更多 driver.execute_script(window.scrollBy(0, 1000);) time.sleep(REQUEST_INTERVAL) scroll_count 1 # 每采集10页清理一次DOM if scroll_count % 10 0: driver.execute_script( const sections document.querySelectorAll(section.note-item); if (sections.length 50) { for (let i 0; i sections.length - 20; i) { sections[i].innerHTML ; } } ) print(f已滚动{scroll_count}页清理DOM内存) # 保存数据 df pd.DataFrame(results) df.to_excel(OUTPUT_EXCEL, indexFalse) print(f采集完成共{len(results)}条数据已保存至{OUTPUT_EXCEL}) driver.quit()这段代码里有两个核心逻辑值得展开讲。第一为什么用no_new_data_count来判断结束因为小红书搜索结果的末尾没有明显的“已加载全部”提示只能通过“翻了几页还没新数据”来推断。我实测下来连续3次滚动无新增数据基本可以确定到底了。如果你想更严谨可以额外解析页面里是否有“没有更多了”这个文案有的话直接退出。第二DOM清理的时机为什么是10页一次因为小红书一页大概增加20-30个卡片节点10页就有两三百个节点清理之前的节点可以维持响应速度同时保留最近20个节点因为你还需要那20个节点来判断是否触底。我试验过5页清理一次更流畅但可能造成快速滚动时上一批数据没来得及解析就没了所以10页是平衡点。5.4 第四步添加请求延时和随机化反爬的核心之一就是请求节奏要像人。我设定了最基础的time.sleep(REQUEST_INTERVAL)但更好的做法是引入随机延时import random def human_delay(): # 模拟人的操作间隔1.5到3.5秒之间随机 delay random.uniform(1.5, 3.5) time.sleep(delay)再配合随机的鼠标移动通过Selenium的ActionChains和随机的滚动速度能更有效地降低被识别为机器的概率。这套机制本质上是在模拟人的阅读行为对平台来说是一个自然的用户而不是一个采集工具。5.5 第五步数据存储到Excel最终的数据存储用了pandas的to_excel这里有一个坑要提醒直接写中文文件名或者中文sheet名在某些环境下会报编码错误。解决方法是df.to_excel(data/notes.xlsx, indexFalse, engineopenpyxl)如果需要写多个sheet或者做格式美化建议用openpyxl直接操作pandas只是一个简化的入口。6. 避坑指南验证码、封号和断点续跑的防守策略做爬虫最怕的不是代码bug而是被对方识别导致IP被限制、账号被封。这一章专门聊防守策略全是我实际跑项目时踩出来的经验。6.1 验证码挡路怎么办遇到滑块验证码不要硬刚。我的策略是第一时间降低采集速度把请求间隔从2秒提高到5秒让风控判定你的行为“慢了”而放松警惕。Selenium模式下如果检测到滑块出现最好的做法是人工介入滑一下。毕设场景下你自己人就在电脑前顺手滑一下就好。这也是用Selenium的一个隐性优势人工介入成本极低。如果频繁触发就换个时间段再跑。小红书的晚高峰20-23点风控最敏感凌晨的宽松度会好很多。尽量不要用自动识别验证码的库去硬解滑块命中率低不说还容易因为移动轨迹太像机器而被拉黑。ddddocr可以识别图形验证码但滑块验证码是另一个维度的问题。6.2 账号被限流了怎么办有一次我压测采集3000条笔记账号直接被限流表现为所有的请求都成功但返回的数据全是重复的或者直接返回空列表。这种情况说明你的账号被标记为“异常流量”不会立刻封号但接口数据会掺水。应对措施就一条立即停止当前账号的使用过24小时再试。如果恢复不了就换账号。所以做毕设或者抓大批量数据前最好想好“多账号轮询”的预案一个主账号采集中等规模数据1000条以下备选账号留着救急。6.3 断点续跑避免前功尽弃采集过程中电脑休眠、断网是家常便饭尤其数据量大的时候跑到一半挂了之前采集的数据就白费了吗所以一定要做断点续跑的机制。我的做法是每采集到10条数据就同步写一次文件存储通过append模式写入CSV而不是最后一次性写入Exceldef append_to_csv(data, filenamedata/notes.csv): import csv file_exists os.path.isfile(filename) with open(filename, a, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnamesdata.keys()) if not file_exists: writer.writeheader() writer.writerow(data)配合检查已采集的链接集合重启后自动跳过已采集的笔记def load_existing_links(): existing set() if os.path.exists(data/notes.csv): df pd.read_csv(data/notes.csv) if 链接 in df.columns: existing set(df[链接].tolist()) return existing这个机制在你的论文里也可以作为一个亮点去写叫“高可用爬虫的设计与实现”答辩的时候能加分。7. 进阶方向别再满足于“下载就能运行”到这里你已经成功跑通了一个基础版的小红书爬虫能按关键词采集数据、能翻页、能存Excel。但这些都还只是开胃菜想让这个项目的价值再上一个台阶有几个进阶方向值得投入时间。7.1 从采集到分析让数据产生价值光有数据不算本事能从数据里提炼出有价值的信息才算。采集到的笔记标题、点赞、评论、收藏这些字段完全可以做一套简单的数据分析统计不同关键词的笔记数量分布看哪个品类在小红书上的内容供给最充足分析点赞量和发布时间的关系总结爆文的时间规律对标题做分词和词频统计提炼热门关键词组合可以给做运营的同学提供选题参考对作者的粉丝数与笔记互动数做相关性分析判断是否存在刷量现象这些都是用pandas加matplotlib就能完成的事情不需要额外的技术栈。但是放到毕业设计里这就从一个“爬虫项目”升级成了“数据采集与分析系统”研究的深度和层次立刻不一样了。7.2 从单机到分布式用Scrapy框架重写现在的代码是“单机单线程”的虽然用Selenium已经绕开了签名校验的难题但扩展性有限。如果想跑更大规模的数据可以考虑用Scrapy框架来重写整个项目。Scrapy是一个成熟的爬虫框架自带分布式扩展能力、去重机制、数据管道、中间件系统。如果我能把Selenium的登录态和Scrapy的异步请求结合起来就能同时解决签名问题和效率问题。比如用Scrapy的Downloader Middleware管理Cookie和请求头用Scrapy的Pipeline做数据清洗和入库用Scrapy的Item定义数据结构配合ItemLoader做字段解析这个方案的代码量更大但工程化程度完全不是同一个量级。如果你的毕设题目允许我强烈建议尝试这个方向答辩老师看了都会眼前一亮。7.3 从小红书到全平台沉淀平台无关的爬虫模型爬虫的能力是可迁移的。你把小红书这套流程跑通之后再去看抖音、微博、知乎、B站的网页版会发现它们的反爬思路和应对方式有很多共性——无非都是登录态管理、动态渲染、参数混淆、频率控制这几件事。所谓“经验丰富”不是掌握了一个网站的破解方法而是积累了一套“遇到反爬怎么分析、怎么绕过、怎么调整”的方法论。比如遇到任何新的目标站先打开开发者工具的Network面板看数据是通过HTML渲染还是XHR接口加载。如果是XHR接口再找签名参数如果签名太难就退回Selenium方案。这套决策流程比任何具体代码都值钱。8. 写在最后项目之外的实话把爬虫这件事放到更大的背景下来看它本质上是“网络公开数据的获取与利用”这个更大的话题的缩影。技术的价值从来不在工具本身而在你用工具解决什么问题的判断力。我在实际跑这个项目的过程中有个很深的体会爬虫写得好不好一半取决于代码一半取决于你对目标平台的了解。你得知道它的搜索规则怎么运转它的推荐算法偏向什么样的内容它的用户习惯在什么时间段活跃。这些东西不需要你去读Paper只需要你以一个普通用户的身份去刷上几天小红书就能积累出感觉。另外一个做毕设的实用建议代码能跑通只是一个基本要求你还要能讲清楚系统里每一个模块为什么这么设计它解决了什么问题有什么可以改进的地方。把自己当成一个“交付系统”的工程师而不是“完成作业”的学生这个思路会让你的毕业设计和面试表现都提升一个档次。最后再分享一个小技巧跑爬虫的时候在代码里加一个优雅退出的机制按一下q就能安全停止采集程序并保存当前进度。我之前写代码的时候总是CtrlC强行中断实验结果丢了一半后来加了这个机制不仅好用写进项目文档里也显得很专业。比如用try/except KeyboardInterrupt配合atexit注册退出时保存数据的回调这个小功能会省掉很多不必要的麻烦。本文还有配套的精品资源点击获取