网站首页 > 技术文章 正文
首先声明:本文章仅限技术研究,不可用于任何违法犯罪!
1、搜索页面关键信息查找
小红书搜索网址:
https://edith.xiaohongshu.com/api/sns/web/v1/search/notes
需要两个参数:一个是cookie,还有一个是搜索关键字
需要登录小红书后方能取得cookie,如何取得cookie,请自行baidu
调用接口的json串
{
"keyword": "搜索关键字",
"page": 1,
"page_size": 20,
"search_id": "2f0e292nup5mqrk8rzhev",
"sort": "general",
"note_type": 0,
"ext_flags": [],
"filters": [
{"tags": ["general"], "type": "sort_type"},
{"tags": ["不限"], "type": "filter_note_type"},
{"tags": ["不限"], "type": "filter_note_time"},
{"tags": ["不限"], "type": "filter_note_range"},
{"tags": ["不限"], "type": "filter_pos_distance"}
],
"geo": "",
"image_formats": ["jpg", "webp", "avif"]
}
请求后可以取得每一条的itemId和token
2、打开每个详细页面取得相关信息
将取得的itemId和token拼成字符串请求#34;
https://www.xiaohongshu.com/explore/{itemId}?xsec_token={token}&xsec_source=pc_search";
cookie也必须带上哦!
请求后取得的responseBody,非常大,再用正值表达式取出核心信息
var result = new Dictionary<string, object>
{
{ "noteId", "" }, //笔记ID
{ "userId", "" }, //当前登录用户ID
{ "user_nickname", "" }, //当前登录用户昵称
{ "og_userId", "" }, //笔记作者ID
{ "og_nickname", "" }, //笔记作者昵称
{ "og_title", "" }, //笔记标题
{ "og_description", "" }, //笔记描述
{ "og_images", new List<string>() },//笔记图片
{ "og_videos", new List<string>() },//笔记视频
{ "thumbsCount", "0" }, //点赞数
{ "collectCount", "0" }, //收藏数
{ "commentCount", "0" }, //回复数
{ "shareCount", "0" } //分享数
};
所有信息的读取从HTML中的__INITIAL_STATE__开始,以上部分都是乱七八糟的代码,我们不用管。
具体代码如下:
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace XiaohongshuSpiderEXE
{
public class ExtractNoteData
{
public static Dictionary<string, object> ExtractNoteDataFromHtml(string htmlContent)
{
var result = new Dictionary<string, object>
{
{ "noteId", "" }, //笔记ID
{ "userId", "" }, //当前登录用户ID
{ "user_nickname", "" }, //当前登录用户昵称
{ "og_userId", "" }, //笔记作者ID
{ "og_nickname", "" }, //笔记作者昵称
{ "og_title", "" }, //笔记标题
{ "og_description", "" }, //笔记描述
{ "og_images", new List<string>() },//笔记图片
{ "og_videos", new List<string>() },//笔记视频
{ "thumbsCount", "0" }, //点赞数
{ "collectCount", "0" }, //收藏数
{ "commentCount", "0" }, //回复数
{ "shareCount", "0" } //分享数
};
// 匹配 noteId
var noteIdMatch = Regex.Match(htmlContent, "\"noteId\":\"([a-fA-F0-9]{24})\"");
string noteId = noteIdMatch.Success ? noteIdMatch.Groups[1].Value : "";
// 提取 og:title 内容
var ogTitleMatch = Regex.Match(htmlContent,
@"<meta[^>]*(name|property)=[\x22\x27]og:title[\x22\x27][^>]*content=[\x22\x27]([^>\x22\x27]*)[\x22\x27]",
RegexOptions.IgnoreCase);
result["og_title"] = ogTitleMatch.Success ? ogTitleMatch.Groups[2].Value : "";
// 提取 og:description 内容
var ogDescMatch = Regex.Match(htmlContent,
@"<meta[^>]*(name|property)=[\x22\x27]og:description[\x22\x27][^>]*content=[\x22\x27]([^>\x22\x27]*)[\x22\x27]",
RegexOptions.IgnoreCase);
result["og_description"] = ogDescMatch.Success ? ogDescMatch.Groups[2].Value : "";
// 提取所有 og:image 内容
var ogImageMatches = Regex.Matches(htmlContent,
@"<meta[^>]*(name|property)=[\x22\x27]og:image[\x22\x27][^>]*content=[\x22\x27]([^>\x22\x27]*)[\x22\x27]",
RegexOptions.IgnoreCase);
var ogImages = new List<string>();
foreach (Match match in ogImageMatches)
{
if (match.Success)
{
ogImages.Add(match.Groups[2].Value);
}
}
result["og_images"] = ogImages;
// 提取所有 og:video 内容
var ogVideoMatches = Regex.Matches(htmlContent,
@"<meta[^>]*(name|property)=[\x22\x27]og:video[\x22\x27][^>]*content=[\x22\x27]([^>\x22\x27]*)[\x22\x27]",
RegexOptions.IgnoreCase);
var ogVideos = new List<string>();
foreach (Match match in ogVideoMatches)
{
if (match.Success)
{
ogVideos.Add(match.Groups[2].Value);
}
}
result["og_videos"] = ogVideos;
// 第一步:提取 <script> 标签内容
string scriptContent = ExtractScriptContent(htmlContent);
if (string.IsNullOrEmpty(scriptContent))
{
Console.WriteLine("未找到包含 __INITIAL_STATE__ 的 <script> 标签");
return result;
}
// 第二步:提取 JSON 字符串
string jsonStr = ExtractInitialJsonFromScript(scriptContent);
if (string.IsNullOrEmpty(jsonStr))
{
Console.WriteLine("未找到 __INITIAL_STATE__ 的 JSON 数据");
return result;
}
// 第三步:解析 JSON 并提取字段
try
{
JObject jObject = JObject.Parse(jsonStr);
// 提取 userInfo 中的 userId 和 nickname
var userInfo = jObject["user"]?["userInfo"] as JObject;
if (userInfo != null)
{
result["userId"] = userInfo["userId"]?.ToString();
result["user_nickname"] = userInfo["nickname"]?.ToString();
}
// 提取 note 下的 noteId, title, desc
var note = jObject["note"]?["noteDetailMap"] as JObject;
if (note != null)
{
foreach (var prop in note.Properties())
{
var noteItem = prop.Value as JObject;
if (noteItem != null && noteItem.ContainsKey("note"))
{
var noteObj = noteItem["note"] as JObject;
if (noteObj != null)
{
result["noteId"] = prop.Name; // noteId 就是属性名
result["og_title"] = noteObj["title"]?.ToString();
result["og_description"] = noteObj["desc"]?.ToString();
// 提取作者信息
var userInNote = noteObj["user"] as JObject;
if (userInNote != null)
{
result["og_userId"] = userInNote["userId"]?.ToString();
result["og_nickname"] = userInNote["nickname"]?.ToString();
}
// 提取互动数据
var interactInfo = noteObj["interactInfo"] as JObject;
if (interactInfo != null)
{
result["thumbsCount"] = interactInfo["likedCount"]?.ToString() ?? "0";
result["collectCount"] = interactInfo["collectedCount"]?.ToString() ?? "0";
result["commentCount"] = interactInfo["commentCount"]?.ToString() ?? "0";
result["shareCount"] = interactInfo["shareCount"]?.ToString() ?? "0";
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("JSON 解析失败:" + ex.Message);
}
return result;
}
private static string ExtractScriptContent(string html)
{
var scriptRegex = new Regex(@"<script[^>]*>(.*?)</script>", RegexOptions.Singleline);
foreach (Match match in scriptRegex.Matches(html))
{
string script = match.Groups[1].Value;
if (script.Contains("__INITIAL_STATE__"))
{
return script;
}
}
return null;
}
private static string ExtractInitialJsonFromScript(string scriptContent)
{
int startIndex = scriptContent.IndexOf("window.__INITIAL_STATE__={");
if (startIndex < 0) return null;
startIndex = scriptContent.IndexOf('{', startIndex);
if (startIndex < 0) return null;
int openBraceCount = 1;
int i = startIndex + 1;
while (i < scriptContent.Length && openBraceCount > 0)
{
if (scriptContent[i] == '{') openBraceCount++;
else if (scriptContent[i] == '}') openBraceCount--;
i++;
}
if (openBraceCount == 0)
{
int length = i - startIndex;
return scriptContent.Substring(startIndex, length);
}
return null;
}
}
}
3、将笔记信息交给AI改写,取得返回信息
再将取得的笔记正文转给AI,进行改写,具体操作请参考“.net core调Dify工作流,返回AI生成的结果” 和 “从零到精通:用Postman调试Dify工作流的实战指南”
4、小红书反读取
小红书机器人反拉取机制,操作慢一点,不然会被强制下线。
再次强调本文章仅限技术研究,不可用于任何违法犯罪行为!
保险利率又在调整了,近期有考虑配置的朋友欢迎咨询!
#Zui懂保险的IT架构师#-----求一键四连:关注、点赞、分享、收藏
猜你喜欢
- 2025-07-23 跨域问题解决方案:JSONP(跨域怎么解决,jsonp原理叙述)
- 2025-07-23 技术总监说:“每一个v-html,都是一个敞开的XSS后门”
- 2025-07-23 浏览器的同源策略与跨域问题(浏览器同源政策)
- 2025-07-23 资源提示关键词:提升页面加载速度的利器
- 2025-07-23 JavaScript DOM 内容操作常用方法和 XSS 注入攻击
- 2025-04-27 JavaScript注释:单行注释和多行注释详解
- 2025-04-27 贼好用的 Java 工具类库
- 2025-04-27 一文搞懂,WAF阻止恶意攻击的8种方法
- 2025-04-27 详细教你微信公众号正文页SVG交互开发
- 2025-04-27 Cookie 和 Session 到底有什么区别?
- 1517℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 594℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 521℃MySQL service启动脚本浅析(r12笔记第59天)
- 489℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 489℃启用MySQL查询缓存(mysql8.0查询缓存)
- 477℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 456℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 454℃MySQL server PID file could not be found!失败
- 最近发表
-
- PS所有滤镜的说明(六)(ps滤镜详解)
- 5款小白也能用的在线图片编辑器!电商效率飙升就靠它!
- Java变量(java变量有什么作用)
- Java面试常见问题:Java注解(java中的面试题)
- Java编程入门第一课:HelloWorld(java编程从入门到实践)
- Java基础教程:Java继承概述(java里继承的概述)
- java基础之——访问修饰符(private/default/protected/public)
- 如何规划一个合理的JAVA项目工程结构
- 将机器指令翻译成 JavaScript -- 终极目标
- Web 服务器基准测试:Go vs. Node.js vs. Nim vs. Bun
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)