网站首页 > 技术文章 正文
首先声明:本文章仅限技术研究,不可用于任何违法犯罪!
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 到底有什么区别?
- 最近发表
-
- count(*)、count1(1)、count(主键)、count(字段) 哪个更快?
- 深入探索 Spring Boot3 中 MyBatis 的 association 标签用法
- js异步操作 Promise fetch API 带来的网络请求变革—仙盟创梦IDE
- HTTP状态码超详细说明_http 状态码有哪些
- 聊聊跨域的原理与解决方法_跨域解决方案及原理
- 告别懵圈!产品新人的接口文档轻松入门指南
- 在Javaweb中实现发送简单邮件_java web发布
- 优化必备基础:Oracle中常见的三种表连接方式
- Oracle常用工具使用 - AWR_oracle工具有哪些
- 搭载USB 3.1接口:msi 微星 发布 990FXA Gaming 游戏主板
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)