This commit is contained in:
2025-05-02 15:39:44 +08:00
parent e58adbc46b
commit ee483aa87e
32 changed files with 919 additions and 621 deletions

View File

@@ -1,6 +1,7 @@
// ErrorTuple and ErrorEnum
const ErrorEnum = {
IP_BLOCK: { code: 300012, msg: '网络连接异常,请检查网络设置或重启试试' },
NOTE_CANT_GET: { code: 300031, msg: '当前笔记暂时无法浏览' },
NOTE_ABNORMAL: { code: -510001, msg: '笔记状态异常,请稍后查看' },
NOTE_SECRETE_FAULT: { code: -510001, msg: '当前内容无法展示' },
SIGN_FAULT: { code: 300015, msg: '浏览器异常,请尝试关闭/卸载风险插件或重启试试!' },

View File

@@ -58,7 +58,12 @@ class XhsClient {
this.cookie = cookie;
}
}
/**
* @params {*} args
*/
printResult(...args) {
//
}
// Getter for cookie
get cookie() {
return this.axiosInstance.defaults.headers.Cookie;
@@ -82,14 +87,11 @@ class XhsClient {
const X_S = x_s_result['X-s'];
const X_t = x_s_result['X-t'].toString();
const X_S_COMMON = getXCommon(a1, b1, X_S, X_t);
// this.axiosInstance.defaults.headers['X-s'] = X_S;
// this.axiosInstance.defaults.headers['X-t'] = X_t;
// this.axiosInstance.defaults.headers['X-s-common'] = X_S_COMMON;
return {
headers: {
'X-s': X_S,
'X-t': X_t,
'X-s-common': X_S_COMMON,
'x-s': X_S,
'x-t': X_t,
'xs-common': X_S_COMMON,
},
};
}
@@ -123,9 +125,11 @@ class XhsClient {
async request(method, url, config = {}) {
try {
const response = await this.axiosInstance({ method, url, ...config });
delete config.sign;
const requestOptions = { method, url, ...config };
this.printResult('request', requestOptions);
const response = await this.axiosInstance(requestOptions);
if (!response.data) return response;
// console.log('response', response)
if (response.status === 471 || response.status === 461) {
const verifyType = response.headers['verifytype'];
const verifyUuid = response.headers['verifyuuid'];
@@ -133,8 +137,12 @@ class XhsClient {
}
const data = response.data;
this.printResult('reponse', {
url: url,
response,
});
if (data.success) {
return data.data || data.success;
return data;
} else if (data.code === ErrorEnum.IP_BLOCK.code) {
throw new IPBlockError(ErrorEnum.IP_BLOCK.msg, response);
} else if (data.code === ErrorEnum.SIGN_FAULT.code) {
@@ -167,9 +175,11 @@ class XhsClient {
if (params) {
uri = `${uri}?${qs.stringify(params)}`;
}
if (config.sign) {
await config.sign(uri, data, config);
} else {
const header = config.headers || {};
const xs = header['x-s'];
if (config.sign && !xs) {
await config.sign(uri, null, config);
} else if (!xs) {
const { headers } = this._preHeaders(uri, null);
config = { ...config, headers: { ...config.headers, ...headers } };
}
@@ -197,9 +207,11 @@ class XhsClient {
async post(uri, data = null, config = {}) {
let jsonStr = data ? JSON.stringify(data) : null;
let endpoint = this._host;
if (config.sign) {
const header = config.headers || {};
const xs = header['x-s'];
if (config.sign && !xs) {
await config.sign(uri, data, config);
} else {
} else if (!xs) {
const { headers } = this._preHeaders(uri, data);
config = { ...config, headers: { ...config.headers, ...headers } };
}
@@ -226,10 +238,11 @@ class XhsClient {
/**
* 获取笔记详情
* 注意: 需要xsec_token
* @uri /api/sns/web/v1/feed
* @param {string} noteId
* @returns
*/
async getNoteById(noteId, xsecToken, xsecSource = 'pc_feed') {
async getNoteById(noteId, xsecToken, xsecSource = 'pc_feed', config = {}) {
if (!xsecToken) {
throw new Error('xsecToken is required');
}
@@ -242,16 +255,24 @@ class XhsClient {
const uri = '/api/sns/web/v1/feed';
try {
const res = await this.post(uri, data);
const res = await this.post(uri, data, config);
return res.items[0].note_card;
} catch (error) {
console.error('Error fetching note:', error);
throw error;
}
}
/**
* 获取笔记详情
* @uri /api/sns/web/v1/feed
* @param {string} noteId
* @param {string} xsecToken
* @param {string} [xsecSource=pc_feed]
* @returns
*/
async getNoteByIdFromHtml(noteId, xsecToken, xsecSource = 'pc_feed') {
const url = `https://www.xiaohongshu.com/explore/${noteId}?xsec_token=${xsecToken}&xsec_source=${xsecSource}`;
this.printResult('html', { url, noteId, xsecToken, xsecSource });
let html = '';
try {
const response = await this.axiosInstance.get(url, {
@@ -283,17 +304,29 @@ class XhsClient {
throw error;
}
}
/**
* 获取用户信息
* @uri /api/sns/web/v1/user/selfinfo
* @returns
*/
async getSelfInfo() {
const uri = '/api/sns/web/v1/user/selfinfo';
return this.get(uri);
}
/**
* @uri /api/sns/web/v2/user/me
* @returns
*/
async getSelfInfoV2() {
const uri = '/api/sns/web/v2/user/me';
return this.get(uri);
}
/**
* 获取用户信息
* @uri /api/sns/web/v1/user/otherinfo
* @param {string} userId
* @returns
*/
async getUserInfo(userId) {
const uri = '/api/sns/web/v1/user/otherinfo';
const params = {
@@ -304,6 +337,7 @@ class XhsClient {
/**
*
* @uri /api/sns/web/v1/search/notes
* @param {string} keyword 关键词
* @param {number} page 页码
* @param {number} pageSize 分页查询的数量
@@ -329,21 +363,26 @@ class XhsClient {
/**
* 获取笔记评论
* @uri /api/sns/web/v2/comment/page
* @param {string} noteId 笔记id
* @param {string} cursor 分页查询的下标,默认为""
* @param {Object} params 其他参数
* @returns
*/
async getNoteComments(noteId, cursor = '') {
async getNoteComments(noteId, cursor = '', otherParams = {}) {
const uri = '/api/sns/web/v2/comment/page';
const params = {
note_id: noteId,
cursor: cursor,
image_formats: 'jpg,webp,avif',
...otherParams,
};
return this.get(uri, params);
}
/**
* 获取用户笔记
* @uri /api/sns/web/v1/user_posted
* @param {*} userId
* @param {*} cursor
* @returns
@@ -361,6 +400,7 @@ class XhsClient {
/**
* 获取账号@我通知
* @uri /api/sns/web/v1/you/mentions
* @param {*} num
* @param {*} cursor
* @returns
@@ -373,6 +413,7 @@ class XhsClient {
/**
* 获取点赞通知
* @uri /api/sns/web/v1/you/likes
* @param {*} num
* @param {*} cursor
* @returns
@@ -385,16 +426,23 @@ class XhsClient {
/**
* 获取关注通知
* @uri /api/sns/web/v1/you/connections
* @param {*} num
* @param {*} cursor
* @returns
*/
async getFollowNotifications(num = 20, cursor = '') {
async getFollowNotifications(num = 20, cursor = '', config = {}) {
const uri = '/api/sns/web/v1/you/connections';
const params = { num: num, cursor: cursor };
return this.get(uri, params);
return this.get(uri, params, config);
}
/**
* 获取用户信息
* @uri /user/profile/{userId}
* @description 通过用户ID获取用户信息
* @param {string} userId
* @returns
*/
async getUserInfoFromHtml(userId) {
const url = `https://www.xiaohongshu.com/user/profile/${userId}`;
try {