新增feapder篇

This commit is contained in:
xishandong 2023-09-09 17:58:12 +08:00
parent b05b90f93a
commit 81b2b492a3
23 changed files with 1005 additions and 1132 deletions

View File

@ -118,6 +118,10 @@ graph TD;
| 大骑士 | 多任务协程 | 基础 | [点这里](https://github.com/xishandong/crawlProject/tree/main/%E5%9F%BA%E7%A1%80%E7%AF%87/%E9%AB%98%E6%80%A7%E8%83%BD%E5%BC%82%E6%AD%A5%E7%88%AC%E8%99%AB) |
| 大骑士 | 线程池应用 | 基础 | [点这里](https://github.com/xishandong/crawlProject/tree/main/%E5%9F%BA%E7%A1%80%E7%AF%87/%E9%AB%98%E6%80%A7%E8%83%BD%E5%BC%82%E6%AD%A5%E7%88%AC%E8%99%AB) |
### feapder
| 难度标识 | 项目名 | 补充 | 快捷导航 |
|----------|---------|-----------------------------------------------------|-------------------------------------------------------------------------------------------------|
| 辉耀骑士 | 小红书数据采集 | 使用air模式的feapder自定义csv储存管道未来会以更多模式改写以及更多功能加入还迎补充 | [点这里](https://github.com/xishandong/crawlProject/tree/main/) |
## 自动化篇
### selenium

View File

@ -0,0 +1,36 @@
from feapder.db.mysqldb import MysqlDB
##############################################################################
# SQL语句
# 创建笔记表
create_note_table_sql = '''
CREATE TABLE IF NOT EXISTS note (
note_id varchar(255) PRIMARY KEY,
note_type varchar(255),
display_title TEXT,
note_cover TEXT,
liked_count INTEGER,
user_name varchar(255),
user_id varchar(255),
avatar TEXT
)
'''
create_note_comment_table_sql = '''
CREATE TABLE IF NOT EXISTS comment (
comment_id varchar(255) PRIMARY KEY,
note_id varchar(255),
target_comment varchar(255),
content TEXT,
like_count varchar(100),
user_name varchar(255),
user_id varchar(255)
)
'''
##############################################################################
if __name__ == '__main__':
db = MysqlDB()
# 创建note表
# db.execute(create_note_table_sql)
# 创建评论表
db.execute(create_note_comment_table_sql)

View File

@ -0,0 +1,23 @@
# RedBook爬虫文档
## 数据库设计
见MYSQLDB文件
## 爬虫逻辑
暂时分为两个部分,获取主页帖子以及获取评论帖子
使用时需要下载feapder
需要nodejs环境
```bash
npm install jsdom
npm install touch-cookie
```
## 项目架构
支持数据库存储
支持csv存储
如果使用mysql需要配置数据库
如果使用csv需要配置csv文件名路径已经做好
并且需要按照js代码的指示完成加密参数生成
## 之后新增
1. 更多功能
2. 用户池
3. ...

View File

@ -0,0 +1,34 @@
import os
from feapder.pipelines import BasePipeline
from feapder.utils.log import log
from RedBook.setting import CSV_PATH
import csv
class CsvPipeline(BasePipeline):
def __init__(self):
path = os.path.abspath(os.path.dirname(__file__) + '/csv_data/' + CSV_PATH)
self.f = open(path, "w", encoding="utf-8", newline='')
self.len = 0
def save_items(self, table, items) -> bool:
try:
header = list(items[0].keys())
writer = csv.DictWriter(self.f, header)
# 如果文件为空,写入表头
if self.len == 0:
writer.writeheader()
self.len = 1
writer.writerows(items)
self.f.flush() # 刷新缓冲区到磁盘
log.info(f"CSV管道 ===> {table},写入csv文件成功")
return True
except Exception as e:
log.error(f"CSV管道 ===> 错误信息: {e}")
log.error(f"CSV管道 ===> {table},写入csv文件失败")
return False
def close(self):
self.f.close()

View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""
Created on 2023-09-09 12:22:13
---------
@summary:
---------
@author: dongxishan
"""
from feapder import Item
class NoteItem(Item):
"""
帖子实体
"""
__table_name__ = "note"
__unique_key__ = "note_id"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.avatar = kwargs.get('avatar')
self.display_title = kwargs.get('display_title')
self.liked_count = kwargs.get('liked_count')
self.note_cover = kwargs.get('note_cover')
self.note_id = kwargs.get('note_id')
self.note_type = kwargs.get('note_type')
self.user_id = kwargs.get('user_id')
self.user_name = kwargs.get('user_name')
class Comment(Item):
"""
评论实体
"""
__table_name__ = "comment"
__unique_key__ = "comment_id"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.note_id = kwargs.get('note_id')
self.comment_id = kwargs.get('comment_id')
self.content = kwargs.get('content')
self.target_comment = kwargs.get('target_comment')
self.user_id = kwargs.get('user_id')
self.user_name = kwargs.get('user_name')

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
"""
Created on 2023-09-05 22:01:40
---------
@summary: 爬虫入口
---------
@author: dong xi shan
"""
if __name__ == "__main__":
pass
# main.py作为爬虫启动的统一入口提供命令行的方式启动多个爬虫若只有一个爬虫可不编写main.py
# 将上面的xxx修改为自己实际的爬虫名
# 查看运行命令 python main.py --help
# AirSpider与Spider爬虫运行方式 python main.py --crawl_xxx
# BatchSpider运行方式
# 1. 下发任务python main.py --crawl_xxx 1
# 2. 采集python main.py --crawl_xxx 2
# 3. 重置任务python main.py --crawl_xxx 3

View File

@ -0,0 +1,7 @@
def add_cookie(request):
# 这个中间件是用来添加cookie的注意此处的cookie需要和js补环境的cookie一致
request.cookies = {
}
return request

View File

@ -0,0 +1,39 @@
import json
import os
from urllib.parse import urlparse, urlencode
import execjs
def get_XsXt(api: str, payload: dict = None) -> dict:
# 获取RedBook/midware/jsCode/jsss.js的绝对路径
js_path: str = os.path.abspath(os.path.dirname(__file__) + '/jsCode/jsss.js')
js = execjs.compile(open(js_path, 'r', encoding='utf-8').read())
# 加密参数
ctx: dict = js.call('XsXt', api, payload)
return {
'x-s': ctx['X-s'],
'x-t': str(ctx['X-t']),
'content-type': 'application/json;charset=UTF-8',
'accept': 'application/json, text/plain, */*',
}
def add_XsXt(request):
url = request.url
parsed_url = urlparse(url)
path = parsed_url.path
method = request.method
if method == 'GET':
# GET请求需要拼接params和url
params = request.params
path = path + '?' + urlencode(params)
request.headers = get_XsXt(path)
elif method == 'POST':
# POST请求需要加密payload
json_data = request.json
request.data = json.dumps(json_data, ensure_ascii=False,
separators=(',', ':')).encode()
request.headers = get_XsXt(path, json_data)
return request

View File

@ -0,0 +1,18 @@
from hashlib import md5
from urllib.parse import urlparse, urlencode
def add_sign(request):
url = request.url
parsed_url = urlparse(url)
path = parsed_url.path
params = request.params
if params:
path += '?' + urlencode(params)
obj = md5()
obj.update(f'{path}WSUDD'.encode('utf-8'))
request.headers = {
'x-sign': 'X' + obj.hexdigest()
}
return request

View File

@ -0,0 +1,249 @@
const {JSDOM} = require('jsdom');
const {CookieJar} = require('tough-cookie');
delete __filename
delete __dirname
const customCookies = [
// 注意此处是列表之前那里是数组这里每一个值是a=b的形式
];
const customLocalStorage = {
}
const cookieJar = new CookieJar();
customCookies.forEach(cookie => {
cookieJar.setCookieSync(cookie, 'https://www.xiaohongshu.com/explore');
});
_xl = function () {
debugger
}
const dom = new JSDOM('<!DOCTYPE html><html lang="zh"><body></body></html>', {
url: 'https://www.xiaohongshu.com/explore',
cookieJar: cookieJar,
pretendToBeVisual: true,
referrer: 'https://www.xiaohongshu.com',
contentType: 'text/html',
});
proxy_ = function (obj) {
return new Proxy(obj, {
set(target, property, value) {
console.table([{"类型": 'set', '调用者': target, "调用属性": property, '设置值': value}])
return Reflect.set(...arguments)
},
get(target, property, receiver) {
if (property.constructor.name === 'Symbol') {
throw new Error('Access to internal property Symbol(impl) is not allowed.');
}
console.table([{"类型": 'get', '调用者': target, "调用属性": property, '获取值': target[property]}])
return target[property]
}
})
}
window = dom.window;
document = window.document;
navigator = window.navigator;
location = window.location;
screen = {
availHeight: 824,
availLeft: 0,
availTop: 0,
availWidth: 1536,
colorDepth: 24,
height: 864,
isExtended: false,
onchange: null,
orientation: {
angle: 0,
onchange: null,
type: 'landscape-primary'
},
pixelDepth: 24,
width: 1536
};
window.devicePixelRatio = 1.25
window.AudioContext = _xl
window.openDatabase = _xl
window.CanvasRenderingContext2D = _xl
window.HTMLCanvasElement = _xl
Object.keys(customLocalStorage).forEach(key => {
dom.window.localStorage.setItem(key, customLocalStorage[key]);
});
Object.defineProperty(navigator, 'platform', {
value: 'Win32',
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'appVersion', {
value: '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'webdriver', {
value: false,
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'languages', {
value: ['zh-CN', 'zh'],
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'language', {
value: 'zh-CN',
configurable: true,
writable: false,
});
Object.defineProperty(navigator, 'connection', {
value: {
downlink: 4.75,
effectiveType: "4g",
onchange: null,
rtt: 200,
saveData: false
},
configurable: true,
writable: false,
});
canvas = {
getContext: function (arg) {
if (arg === 'webgl') {
return webgl
}
return null
},
}
webgl = {
canvas: canvas,
drawingBufferColorSpace: "srgb",
drawingBufferHeight: 150,
drawingBufferWidth: 300,
unpackColorSpace: "srgb",
getExtension: function (arg) {
return {}
},
getParameter: function (arg) {
if (arg === undefined) {
throw new Error("Uncaught TypeError: Failed to execute 'getParameter' on 'WebGLRenderingContext': 1 argument required, but only 0 present.")
}
}
}
HTMLImageElement = function HTMLImageElement() {
}
img = {
tagName: 'IMG',
__proto__: HTMLImageElement.prototype,
}
var img = proxy_(img)
var createElement = function createElement(arg) {
if (arg === 'div') {
return {
tagName: 'DIV',
appendChild: function (arg) {
if (arg.tagName === 'DIV') {
throw new Error("Uncaught")
}
},
style: {},
offsetHeight: 0
}
} else if (arg === 'img') {
return img
} else if (arg === 'canvas') {
return canvas
} else if (arg === 'a') {
return {
tagName: 'A'
}
} else if (arg === 'p') {
return {
tagName: 'P'
}
} else if (arg === 'h1') {
return {
tagName: 'H1'
}
} else if (arg === 'h2') {
return {
tagName: 'H2'
}
} else if (arg === 'h3') {
return {
tagName: 'H3'
}
} else if (arg === 'h4') {
return {
tagName: 'H4'
}
} else if (arg === 'span') {
return {
tagName: 'SPAN',
}
} else if (arg === 'ul') {
return {
tagName: 'UL',
}
} else if (arg === 'li') {
return {
tagName: 'LI',
}
} else {
throw new Error('Uncaught DOMException: Failed to execute \'createElement\' on \'Document\': The tag name provided (\'[object HTMLDocument]\') is not a valid name.');
}
}
document.createElement = createElement
var Object_toString = Object.prototype.toString;
Object.prototype.toString = function () {
let temp = Object_toString.call(this, arguments);
if (temp === '[object global]' || temp === '[object Window]') {
return '[object Window]'
} else if (this.constructor.name === 'String') {
return this.valueOf()
} else if (this.constructor.name === 'Cookie') {
return '[object Object]'
} else {
return temp
}
}
var Function_toString = Function.prototype.toString;
Function.prototype.toString = function () {
let temp = Function_toString.call(this, arguments);
if (this.name === 'Window') {
return 'function window() { [native code] }'
} else {
return temp
}
}
;
// 此处自行下载关键加密代码
var a = XsXt('/api/sns/web/v1/feed', {source_note_id: '64bf47e3000000001201a95c'})
console.log(a)
function XsXt(e, t) {
return window._webmsxyw(e, t)
}

View File

@ -0,0 +1,191 @@
# -*- coding: utf-8 -*-
"""爬虫配置文件"""
import os
import sys
#
# MYSQL
MYSQL_IP = "localhost"
MYSQL_PORT = 3306
MYSQL_DB = "redbook"
MYSQL_USER_NAME = "root"
MYSQL_USER_PASS = "*******"
#
# # MONGODB
# MONGO_IP = "localhost"
# MONGO_PORT = 27017
# MONGO_DB = ""
# MONGO_USER_NAME = ""
# MONGO_USER_PASS = ""
#
# # REDIS
# # ip:port 多个可写为列表或者逗号隔开 如 ip1:port1,ip2:port2 或 ["ip1:port1", "ip2:port2"]
# REDISDB_IP_PORTS = "localhost:6379"
# REDISDB_USER_PASS = ""
# REDISDB_DB = 0
# # 连接redis时携带的其他参数如ssl=True
# REDISDB_KWARGS = dict()
# # 适用于redis哨兵模式
# REDISDB_SERVICE_NAME = ""
#
# # 数据入库的pipeline可自定义默认MysqlPipeline
ITEM_PIPELINES = [
"feapder.pipelines.mysql_pipeline.MysqlPipeline",
# "feapder.pipelines.mongo_pipeline.MongoPipeline",
# "feapder.pipelines.console_pipeline.ConsolePipeline",
"RedBook.custom_pipeline.csvPipeline.CsvPipeline",
]
# 配合csv pipeline使用指定需要保存的csv名称默认default.csv
CSV_PATH = 'comment.csv'
# EXPORT_DATA_MAX_FAILED_TIMES = 10 # 导出数据时最大的失败次数,包括保存和更新,超过这个次数报警
# EXPORT_DATA_MAX_RETRY_TIMES = 10 # 导出数据时最大的重试次数,包括保存和更新,超过这个次数则放弃重试
#
# # 爬虫相关
# # COLLECTOR
# COLLECTOR_TASK_COUNT = 32 # 每次获取任务数量追求速度推荐32
#
# # SPIDER
# SPIDER_THREAD_COUNT = 1 # 爬虫并发数追求速度推荐32
# 下载时间间隔 单位秒。 支持随机 如 SPIDER_SLEEP_TIME = [2, 5] 则间隔为 2~5秒之间的随机数包含2和5
SPIDER_SLEEP_TIME = [2, 5]
SPIDER_MAX_RETRY_TIMES = 5 # 每个请求最大重试次数
KEEP_ALIVE = False # 爬虫是否常驻
# 下载
# DOWNLOADER = "feapder.network.downloader.RequestsDownloader" # 请求下载器
# SESSION_DOWNLOADER = "feapder.network.downloader.RequestsSessionDownloader"
# RENDER_DOWNLOADER = "feapder.network.downloader.SeleniumDownloader" # 渲染下载器
# # RENDER_DOWNLOADER="feapder.network.downloader.PlaywrightDownloader"
# MAKE_ABSOLUTE_LINKS = True # 自动转成绝对连接
# # 浏览器渲染
# WEBDRIVER = dict(
# pool_size=1, # 浏览器的数量
# load_images=True, # 是否加载图片
# user_agent=None, # 字符串 或 无参函数返回值为user_agent
# proxy=None, # xxx.xxx.xxx.xxx:xxxx 或 无参函数,返回值为代理地址
# headless=False, # 是否为无头浏览器
# driver_type="CHROME", # CHROME、PHANTOMJS、FIREFOX
# timeout=30, # 请求超时时间
# window_size=(1024, 800), # 窗口大小
# executable_path=None, # 浏览器路径,默认为默认路径
# render_time=0, # 渲染时长,即打开网页等待指定时间后再获取源码
# custom_argument=[
# "--ignore-certificate-errors",
# "--disable-blink-features=AutomationControlled",
# ], # 自定义浏览器渲染参数
# xhr_url_regexes=None, # 拦截xhr接口支持正则数组类型
# auto_install_driver=True, # 自动下载浏览器驱动 支持chrome 和 firefox
# download_path=None, # 下载文件的路径
# use_stealth_js=False, # 使用stealth.min.js隐藏浏览器特征
# )
#
# PLAYWRIGHT = dict(
# user_agent=None, # 字符串 或 无参函数返回值为user_agent
# proxy=None, # xxx.xxx.xxx.xxx:xxxx 或 无参函数,返回值为代理地址
# headless=False, # 是否为无头浏览器
# driver_type="chromium", # chromium、firefox、webkit
# timeout=30, # 请求超时时间
# window_size=(1024, 800), # 窗口大小
# executable_path=None, # 浏览器路径,默认为默认路径
# download_path=None, # 下载文件的路径
# render_time=0, # 渲染时长,即打开网页等待指定时间后再获取源码
# wait_until="networkidle", # 等待页面加载完成的事件,可选值:"commit", "domcontentloaded", "load", "networkidle"
# use_stealth_js=False, # 使用stealth.min.js隐藏浏览器特征
# page_on_event_callback=None, # page.on() 事件的回调 如 page_on_event_callback={"dialog": lambda dialog: dialog.accept()}
# storage_state_path=None, # 保存浏览器状态的路径
# url_regexes=None, # 拦截接口,支持正则,数组类型
# save_all=False, # 是否保存所有拦截的接口, 配合url_regexes使用为False时只保存最后一次拦截的接口
# )
#
# # 爬虫启动时重新抓取失败的requests
# RETRY_FAILED_REQUESTS = False
# # 爬虫启动时重新入库失败的item
# RETRY_FAILED_ITEMS = False
# # 保存失败的request
# SAVE_FAILED_REQUEST = True
# # request防丢机制。指定的REQUEST_LOST_TIMEOUT时间内request还没做完会重新下发 重做)
# REQUEST_LOST_TIMEOUT = 600 # 10分钟
# # request网络请求超时时间
# REQUEST_TIMEOUT = 22 # 等待服务器响应的超时时间,浮点数,或(connect timeout, read timeout)元组
# # item在内存队列中最大缓存数量
# ITEM_MAX_CACHED_COUNT = 5000
# # item每批入库的最大数量
# ITEM_UPLOAD_BATCH_MAX_SIZE = 1000
# # item入库时间间隔
# ITEM_UPLOAD_INTERVAL = 1
# # 内存任务队列最大缓存的任务数默认不限制仅对AirSpider有效。
# TASK_MAX_CACHED_SIZE = 0
#
# # 下载缓存 利用redis缓存但由于内存大小限制所以建议仅供开发调试代码时使用防止每次debug都需要网络请求
# RESPONSE_CACHED_ENABLE = False # 是否启用下载缓存 成本高的数据或容易变需求的数据建议设置为True
# RESPONSE_CACHED_EXPIRE_TIME = 3600 # 缓存时间 秒
# RESPONSE_CACHED_USED = False # 是否使用缓存 补采数据时可设置为True
#
# # 设置代理
# PROXY_EXTRACT_API = None # 代理提取API ,返回的代理分割符为\r\n
# PROXY_ENABLE = True
# PROXY_MAX_FAILED_TIMES = 5 # 代理最大失败次数,超过则不使用,自动删除
# PROXY_POOL = "feapder.network.proxy_pool.ProxyPool" # 代理池
#
# # 随机headers
# RANDOM_HEADERS = True
# # # UserAgent类型 支持 'chrome', 'opera', 'firefox', 'internetexplorer', 'safari''mobile' 若不指定则随机类型
# USER_AGENT_TYPE = "chrome"
# # # 默认使用的浏览器头
# DEFAULT_USERAGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
# # # requests 使用session
# USE_SESSION = False
#
# # 去重
# ITEM_FILTER_ENABLE = False # item 去重
# REQUEST_FILTER_ENABLE = False # request 去重
# ITEM_FILTER_SETTING = dict(
# filter_type=1 # 永久去重BloomFilter = 1 、内存去重MemoryFilter = 2、 临时去重ExpireFilter= 3、轻量去重LiteFilter= 4
# )
# REQUEST_FILTER_SETTING = dict(
# filter_type=3, # 永久去重BloomFilter = 1 、内存去重MemoryFilter = 2、 临时去重ExpireFilter= 3、 轻量去重LiteFilter= 4
# expire_time=2592000, # 过期时间1个月
# )
#
# # 报警 支持钉钉、飞书、企业微信、邮件
# # 钉钉报警
# DINGDING_WARNING_URL = "" # 钉钉机器人api
# DINGDING_WARNING_PHONE = "" # 报警人 支持列表,可指定多个
# DINGDING_WARNING_ALL = False # 是否提示所有人, 默认为False
# # 飞书报警
# # https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN#e1cdee9f
# FEISHU_WARNING_URL = "" # 飞书机器人api
# FEISHU_WARNING_USER = None # 报警人 {"open_id":"ou_xxxxx", "name":"xxxx"} 或 [{"open_id":"ou_xxxxx", "name":"xxxx"}]
# FEISHU_WARNING_ALL = False # 是否提示所有人, 默认为False
# # 邮件报警
# EMAIL_SENDER = "" # 发件人
# EMAIL_PASSWORD = "" # 授权码
# EMAIL_RECEIVER = "" # 收件人 支持列表,可指定多个
# EMAIL_SMTPSERVER = "smtp.163.com" # 邮件服务器 默认为163邮箱
# # 企业微信报警
# WECHAT_WARNING_URL = "" # 企业微信机器人api
# WECHAT_WARNING_PHONE = "" # 报警人 将会在群内@此人, 支持列表,可指定多人
# WECHAT_WARNING_ALL = False # 是否提示所有人, 默认为False
# # 时间间隔
# WARNING_INTERVAL = 3600 # 相同报警的报警时间间隔,防止刷屏; 0表示不去重
# WARNING_LEVEL = "DEBUG" # 报警级别, DEBUG / INFO / ERROR
# WARNING_FAILED_COUNT = 1000 # 任务失败数 超过WARNING_FAILED_COUNT则报警
#
# LOG_NAME = os.path.basename(os.getcwd())
# LOG_PATH = "log/%s.log" % LOG_NAME # log存储路径
LOG_LEVEL = "DEBUG" #
LOG_COLOR = True # 是否带有颜色
LOG_IS_WRITE_TO_CONSOLE = True # 是否打印到控制台
LOG_IS_WRITE_TO_FILE = False # 是否写文件
# LOG_MODE = "w" # 写文件的模式
# LOG_MAX_BYTES = 10 * 1024 * 1024 # 每个日志文件的最大字节数
# LOG_BACKUP_COUNT = 20 # 日志文件保留数量
# LOG_ENCODING = "utf8" # 日志文件编码
# OTHERS_LOG_LEVAL = "ERROR" # 第三方库的log等级
#
# # 切换工作路径为当前项目路径
# project_path = os.path.abspath(os.path.dirname(__file__))
# os.chdir(project_path) # 切换工作路经
# sys.path.insert(0, project_path)
# print("当前工作路径为 " + os.getcwd())

View File

@ -0,0 +1,4 @@
__all__ = [
"get_homefeed",
"test_spider"
]

View File

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
"""
Created on 2023-09-09 16:11:59
---------
@summary:
---------
@author: dongxishan
"""
from typing import Union
import feapder
from RedBook.items.items import Comment
from RedBook.midware.add_cookie import add_cookie
from RedBook.midware.get_XsXt import add_XsXt
from RedBook.types.QueryJsonType import QueryNoteComment, QueryNoteSubComment
class GetComment(feapder.AirSpider):
name = "get_comment"
def __init__(self, notes: Union[str, list], **kwargs):
super().__init__(**kwargs)
self.notes = notes
def start_requests(self):
if isinstance(self.notes, str):
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v2/comment/page",
method='GET',
params=QueryNoteComment(
note_id=self.notes,
cursor=''
),
download_midware=[add_cookie, add_XsXt]
)
elif isinstance(self.notes, list):
for id in self.notes:
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v2/comment/page",
method='GET',
params=QueryNoteComment(
note_id=id,
cursor=''
),
download_midware=[add_cookie, add_XsXt]
)
def parse(self, request, response):
resp = response.json
note_id = request.params.get('note_id')
has_more = resp.get('data', {}).get('has_more')
if has_more:
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v2/comment/page",
method='GET',
params=QueryNoteComment(
note_id=note_id,
cursor=resp['data']['cursor']
),
download_midware=[add_cookie, add_XsXt]
)
data = resp.get('data', {}).get('comments')
for comment in data:
yield from self.parse_comment(note_id, comment)
def parse_comment(self, note_id: str, comment: dict):
# 子评
if comment.get('target_comment', {}):
target_comment = comment.get('target_comment', {}).get('id')
else:
target_comment = 'root_comment'
root_id = None
# 传递第一次的子评论
if comment.get('sub_comments'):
root_id = comment['id']
for sub_comment in comment['sub_comments']:
yield from self.parse_comment(note_id, sub_comment)
# 点击更多
if comment.get('sub_comment_has_more') and root_id:
sub_comment_cursor = comment.get('sub_comment_cursor')
root_comment_id = root_id
yield from self.start_more_comment(sub_comment_cursor, note_id, root_comment_id)
yield Comment(
note_id=note_id,
target_comment=target_comment,
comment_id=comment['id'],
content=comment['content'],
like_count=comment['like_count'],
user_id=comment['user_info']['user_id'],
user_name=comment['user_info']['nickname'],
)
def start_more_comment(self, cursor, note_id, root_id):
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v2/comment/sub/page",
method='GET',
params=QueryNoteSubComment(
note_id=note_id,
cursor=cursor,
num='10',
root_comment_id=root_id
),
download_midware=[add_cookie, add_XsXt],
callback=self.parse_sub_comment
)
def parse_sub_comment(self, request, response):
resp = response.json
has_more = resp.get('data', {}).get('has_more')
if has_more:
yield from self.start_more_comment(
cursor=resp['data']['cursor'],
note_id=request.params.get('note_id'),
root_id=request.params.get('root_comment_id')
)
data = resp.get('data', {}).get('comments')
for comment in data:
yield from self.parse_comment(request.params.get('note_id'), comment)
if __name__ == "__main__":
GetComment(
['64cb8674000000000b02b8de', '64a7e168000000000f00efcb', '64eca3da000000001f03d11b'],
thread_count=10
).start()

View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
"""
Created on 2023-09-08 19:08:21
---------
@summary:
---------
@author: dongxishan
"""
import feapder
from feapder.utils.log import log
from RedBook.items.items import NoteItem
from RedBook.midware.add_cookie import add_cookie
from RedBook.midware.get_XsXt import add_XsXt
from RedBook.types.QueryJsonType import QueryHomeFeedNote
from RedBook.setting import CSV_PATH, ITEM_PIPELINES
class GetHomeFeed(feapder.AirSpider):
MAPPING: dict = dict(zip(
range(10),
[
'homefeed_recommend', 'homefeed.fashion_v3', 'homefeed.food_v3', 'homefeed.cosmetics_v3',
'homefeed.movie_and_tv_v3', 'homefeed.career_v3', 'homefeed.love_v3',
'homefeed.household_product_v3', 'homefeed.gaming_v3', 'homefeed.travel_v3', 'homefeed.fitness_v3'
]
))
# 默认采集主页推荐
QUERY = QueryHomeFeedNote(
cursor_score='',
num=36,
refresh_type=1,
note_index=29,
unread_begin_note_id='',
unread_end_note_id='',
unread_note_count=0,
category='homefeed_recommend'
)
def __init__(self, types: int = 0):
super().__init__()
self.QUERY['category'] = self.MAPPING[types]
if "RedBook.custom_pipeline.csvPipeline.CsvPipeline" in ITEM_PIPELINES:
log.info("csvPipeline已启用, 保存文件路径为: RedBook/custom/csv_data/{}".format(CSV_PATH))
def start_requests(self):
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v1/homefeed",
method='POST',
json=self.QUERY,
download_midware=[add_cookie, add_XsXt]
)
def parse(self, request, response):
resp = response.json
cursor_score = resp.get('data', {}).get('cursor_score')
if cursor_score:
self.QUERY['cursor_score'] = cursor_score
yield feapder.Request(
url="https://edith.xiaohongshu.com/api/sns/web/v1/homefeed",
method='POST',
json=self.QUERY,
download_midware=[add_cookie, add_XsXt]
)
data = resp.get('data', {}).get('items')
for note in data:
if note.get('hot_query'):
continue
else:
yield self.parse_dict(note)
@staticmethod
def parse_dict(note: dict) -> NoteItem:
id = note.get('id')
note = note.get('note_card')
user_name = note.get('user', {}).get('nick_name')
if not user_name:
user_name = note.get('user', {}).get('nickname')
return NoteItem(
note_id=id,
note_type=note.get('type'),
display_title=note.get('display_title'),
note_cover=note.get('cover', {}).get('url'),
liked_count=note.get('interact_info', {}).get('liked_count'),
user_name=user_name,
user_id=note.get('user', {}).get('user_id'),
avatar=note.get('user', {}).get('avatar')
)
if __name__ == "__main__":
GetHomeFeed(0).start()

View File

@ -0,0 +1,69 @@
from typing import TypedDict, Literal
class QueryTopicNote(TypedDict):
"""
话题请求类型
"""
page_size: int # 每页大小
sort: Literal['hot', 'time'] # 话题类型
page_id: str # 话题的id
cursor: str # 话题位移
sid: str # 暂时不清楚
class QueryHomeFeedNote(TypedDict):
"""
首页请求类型
"""
category: Literal[
'homefeed_recommend', 'homefeed.fashion_v3', 'homefeed.food_v3', 'homefeed.cosmetics_v3',
'homefeed.movie_and_tv_v3', 'homefeed.career_v3', 'homefeed.love_v3',
'homefeed.household_product_v3','homefeed.gaming_v3', 'homefeed.travel_v3', 'homefeed.fitness_v3'
]
cursor_score: str
num: int
refresh_type: int
note_index: Literal[29]
unread_begin_note_id: Literal['']
unread_end_note_id: Literal['']
unread_note_count: Literal[0]
class QueryUserInfo(TypedDict):
"""
用户信息请求类型
"""
pass
class QueryNoteDetail(TypedDict):
"""
笔记详情请求类型
"""
pass
class QueryUserNote(TypedDict):
"""
用户笔记请求类型
"""
pass
class QueryNoteComment(TypedDict):
"""
笔记评论请求类型
"""
note_id: str
cursor: str
class QueryNoteSubComment(TypedDict):
"""
笔记评论请求类型
"""
note_id: str
cursor: str
root_comment_id: str
num: str

View File

@ -1,501 +0,0 @@
const crypto = require('cryptojs').Crypto
var window = {}
!function (e, t) { // 21423
var r = 637, n = 526, o = 586, i = 638, a = 650, s = 644, u = 665, l = 601, c = 748, p = 735, d = 759, f = 395,
g = 587, _ = 743, h = 640, m = 767, v = 581, y = 789, b = {
_0x502c22: 360
}, w = e();
function x(e, t) {
return a0_0x320a(t - b._0x502c22, e)
}
for (; ;) try {
if (821175 === parseInt(x(r, n)) * (parseInt(x(o, 525)) / 2) + parseInt(x(i, a)) / 3 + parseInt(x(s, u)) / 4 * (parseInt(x(l, c)) / 5) + -parseInt(x(p, d)) / 6 + -parseInt(x(f, g)) / 7 + -parseInt(x(_, h)) / 8 * (parseInt(x(m, v)) / 9) + parseInt(x(y, 745)) / 10) break;
w.push(w.shift())
} catch (S) {
w.push(w.shift())
}
}(a0_0x5097);
for (var lookup = [], code = a0_0x1c067e(349, 375) + a0_0x1c067e(153, 154) + a0_0x1c067e(497, 476) + a0_0x1c067e(460, 463) + a0_0x1c067e(425, 524) + a0_0x1c067e(401, 285) + a0_0x1c067e(281, 430) + a0_0x1c067e(249, 377) + a0_0x1c067e(225, 360) + "5", i = 0, len = code[a0_0x1c067e(305, 424)]; i < len; ++i) lookup[i] = code[i];
function encodeChunk(e, t, r) {
var n = 583, o = 434, i = 111, a = 162, s = 440, u = 237, l = 182, c = 157, p = 460, d = 406, f = 434, g = 162,
_ = 237, h = 286, m = 422, v = 162, y = 246, b = 247, w = 331, x = 419, S = 297, T = {
_0x17f626: 662
}, E = {};
function k(e, t) {
return a0_0x1c067e(e, t - -T._0x17f626)
}
E[k(-460, -281)] = function (e, t) {
return e < t
}
, E[k(-n, -o)] = function (e, t) {
return e + t
}
, E[k(-i, -a)] = function (e, t) {
return e + t
}
, E[k(-393, -s)] = function (e, t) {
return e & t
}
, E[k(-310, -u)] = function (e, t) {
return e << t
}
, E[k(-l, -c)] = function (e, t) {
return e & t
};
for (var I, A = E, L = [], C = t; A[k(-p, -281)](C, r); C += 3) I = A[k(-d, -f)](A[k(-266, -g)](A[k(-589, -s)](A[k(-395, -_)](e[C], 16), 16711680), A[k(-h, -c)](A[k(-m, -_)](e[A[k(-167, -v)](C, 1)], 8), 65280)), A[k(-94, -c)](e[A[k(-y, -v)](C, 2)], 255)), L[k(-b, -w)](tripletToBase64(I));
return L[k(-x, -S)]("")
}
function xb() {
var Re = "abcdef0123456789"
, je = 16;
for (var e = "", t = 0; t < 16; t++)
e += Re.charAt(Math.floor(Math.random() * je));
return e
}
function tripletToBase64(e) {
var t = 339, r = 525, n = 420, o = 517, i = 423, a = 567, s = 451, u = 428, l = 642, c = 555, p = 511, d = {};
d[g(353, 403)] = function (e, t) {
return e + t
}
, d[g(t, 451)] = function (e, t) {
return e & t
}
, d[g(r, n)] = function (e, t) {
return e >> t
}
, d[g(o, i)] = function (e, t) {
return e & t
};
var f = d;
function g(e, t) {
return a0_0x1c067e(e, t - -34)
}
return f[g(a, 403)](lookup[e >> 18 & 63] + lookup[f[g(306, s)](f[g(u, n)](e, 12), 63)] + lookup[f[g(l, s)](f[g(c, n)](e, 6), 63)], lookup[f[g(p, 423)](e, 63)])
}
function a0_0x320a(e, t) { // 21656
var r = a0_0x5097();
return (a0_0x320a = function (e, t) {
return r[e -= 120]
})(e, t)
}
function encodeUtf8(e) {
for (var t = 478, r = 497, n = 515, o = 454, i = 620, a = 625, s = 751, u = 751, l = 590, c = 499, p = 424, d = {
_0x344d2e: 921
}, f = {
fucJw: function (e, t) {
return e(t)
}, Swqax: function (e, t) {
return e < t
}, ctMjx: function (e, t) {
return e + t
}
}, g = f[b(-330, -510)](encodeURIComponent, e), _ = [], h = 0; f[b(-t, -557)](h, g[b(-306, -r)]); h++) {
var m = g[b(-581, -n)](h);
if ("%" === m) {
var v = g[b(-o, -n)](h + 1) + g[b(-i, -515)](f[b(-a, -s)](h, 2)), y = parseInt(v, 16);
_[b(-u, -l)](y), h += 2
} else _[b(-618, -590)](m[b(-c, -478) + b(-406, -p)](0))
}
function b(e, t) {
return a0_0x1c067e(e, t - -d._0x344d2e)
}
return _
}
function b64Encode(e) {
for (var t, r = 739, n = 556, o = 441, i = 361, a = 295, s = 716, u = 592, l = 393, c = 454, p = 290, d = 464, f = 448, g = 559, _ = 441, h = 590, m = 630, v = 697, y = 566, b = 296, w = 475, x = 414, S = 739, T = 630, E = 312, k = 271, I = 417, A = 271, L = 250, C = 243, O = 412, M = 398, N = 613, R = 465, j = 430, F = 474, P = 551, D = 586, B = 475, U = {
_0x368b07: 110
}, W = {
gpiIM: function (e, t) {
return e % t
}, EibBa: function (e, t) {
return e - t
}, WsrUX: function (e, t, r, n) {
return e(t, r, n)
}, AevWy: function (e, t) {
return e > t
}, ipvBe: function (e, t) {
return e + t
}, ZhKyU: function (e, t) {
return e + t
}, VNtTi: function (e, t) {
return e === t
}, WTFnk: function (e, t) {
return e - t
}, ngGUy: function (e, t) {
return e + t
}, pGzZe: function (e, t) {
return e & t
}, hDlaO: function (e, t) {
return e << t
}, ykUYK: function (e, t) {
return e === t
}, IcWsv: function (e, t) {
return e << t
}, BRIIp: function (e, t) {
return e - t
}, onNTY: function (e, t) {
return e + t
}, TgTiy: function (e, t) {
return e + t
}, pZhfi: function (e, t) {
return e >> t
}, IZpjq: function (e, t) {
return e & t
}, Kollm: function (e, t) {
return e & t
}
}, H = e[Z(395, 534)], G = W[Z(r, n)](H, 3), z = [], V = 16383, q = 0, $ = W[Z(450, 502)](H, G); q < $; q += V) z[Z(373, o)](W[Z(i, a)](encodeChunk, e, q, W[Z(s, u)](W[Z(l, c)](q, V), $) ? $ : W[Z(p, 275)](q, V)));
function Z(e, t) {
return a0_0x1c067e(e, t - U._0x368b07)
}
return W[Z(368, d)](G, 1) ? (t = e[W[Z(f, 327)](H, 1)], z[Z(g, _)](W[Z(h, m)](lookup[t >> 2] + lookup[W[Z(v, y)](W[Z(418, b)](t, 4), 63)], "=="))) : W[Z(w, x)](G, 2) && (t = W[Z(S, T)](W[Z(E, 417)](e[W[Z(311, k)](H, 2)], 8), e[W[Z(I, A)](H, 1)]), z[Z(L, 441)](W[Z(C, O)](W[Z(385, M)](lookup[W[Z(N, 551)](t, 10)], lookup[W[Z(R, j)](W[Z(F, P)](t, 4), 63)]), lookup[W[Z(397, 450)](W[Z(D, 417)](t, 2), 63)]) + "=")), z[Z(452, B)]("")
}
var mcr = function (e) { //21876
var t = 798, r = 958, n = 957, o = 1045, i = 1035, a = 959, s = 713, u = 674, l = 736, c = 585, p = 821, d = 854,
f = 690, g = 707, _ = 831, h = 785, m = 847, v = 1001, y = 1010, b = 729, w = 785, x = 797, S = 960, T = 480,
E = 518, k = 634, I = 435, A = 460, L = 406, C = 577, O = 724, M = 696, N = 680, R = 488, j = 556, F = 479,
P = 718, D = 376, B = 574, U = 418, W = 761, H = 489, G = {
_0x5761f9: 1432
}, z = {
_0xbb1fad: 529
};
function V(e, t) {
return a0_0x1c067e(t, e - z._0xbb1fad)
}
var q = {};
q[V(952, 1089)] = function (e, t) {
return e === t
}
, q[V(t, r)] = V(n, o), q[V(i, 854)] = function (e, t) {
return e & t
}
, q[V(858, a)] = function (e, t) {
return e >>> t
}
, q[V(s, u)] = function (e, t) {
return e ^ t
}
, q[V(l, c)] = function (e, t) {
return e ^ t
}
, q[V(944, p)] = function (e, t) {
return e < t
}
, q[V(d, f)] = function (e, t) {
return e ^ t
}
, q[V(g, _)] = function (e, t) {
return e >>> t
}
, q[V(h, m)] = function (e, t) {
return e & t
}
, q[V(v, y)] = function (e, t) {
return e >>> t
};
for (var $, Z, Y = q, X = 3988292384, K = 256, J = []; K--; J[K] = Y[V(707, b)]($, 0)) for (Z = 8, $ = K; Z--;) $ = Y[V(w, 694)]($, 1) ? Y[V(854, x)](Y[V(1001, S)]($, 1), X) : $ >>> 1;
return function (e) {
function t(e, t) {
return V(e - -G._0x5761f9, t)
}
if (Y[t(-T, -E)](typeof (e), Y[t(-k, -759)])) {
for (var r = 0, n = -1; r < e[t(-479, -649)]; ++r) n = J[Y[t(-397, -I)](n, 255) ^ e[t(-A, -446) + t(-L, -C)](r)] ^ Y[t(-574, -671)](n, 8);
return Y[t(-719, -O)](Y[t(-M, -N)](n, -1), X)
}
for (r = 0, n = -1; Y[t(-R, -j)](r, e[t(-F, -426)]); ++r) n = J[Y[t(-M, -P)](Y[t(-397, -D)](n, 255), e[r])] ^ Y[t(-B, -U)](n, 8);
return Y[t(-696, -W)](Y[t(-578, -H)](n, -1), X)
}
}()
function md5(text) {
text = String(text)
console.log(text)
return crypto.MD5(text).toString()
}
function a0_0x1c067e(e, t) {
return a0_0x320a(t - 34, e)
}
function sign(e, t) { // 23885
var r = 1259, n = 1140, o = 1084, i = 1130, a = 1137, s = 1082, u = 1341, l = 1210, c = 1366, p = 1246, d = 1163,
f = 1328, g = 1218, _ = 1052, h = 1255, m = 1098, v = 1033, y = 1180, b = 1409, w = 1380, x = 1345, S = 1120,
T = 1067, E = 1322, k = 1236, I = 1179, A = 1214, L = 1260, C = 1179, O = 1284, M = 1299, N = 1249, R = 1228,
j = 1197, F = 1370, P = 1148, D = 1238, B = 1420, U = 1398, W = 1258, H = 1166, G = 1153, z = 1106, V = 1234,
q = 1098, $ = 1388, Z = 1119, Y = 1252, X = 1164, K = 1288, J = 1279, Q = 1134, ee = 1356, te = 1346, re = 1519,
ne = 1185, oe = 1105, ie = 1185, ae = 1355, se = 1171, ue = 1124, le = 1202, ce = 984, pe = 1370, de = 1174,
fe = 1357, ge = 822, _e = 837, he = 1151, me = 1101, ve = 1056, ye = 1075, be = 983, we = 1129, xe = 965,
Se = 868, Te = 1263, Ee = 982, ke = 1135, Ie = 1101, Ae = 1001, Le = 940, Ce = 879, Oe = 943, Me = 964,
Ne = 896, Re = 1116, je = 1146, Fe = 1076, Pe = 1116, De = 687, Be = 811, Ue = 913, We = 896, He = 1048,
Ge = 970, ze = 963, Ve = 759, qe = 955, $e = 1116, Ze = 911, Ye = 1153, Xe = 1074, Ke = 1465, Je = 495, Qe = {
_0x506874: 760
}, et = 1011, tt = 1078, rt = 801, nt = 989, ot = 738, it = 624, at = 455, st = 278, ut = 656, lt = 555, ct = {
_0x48dbd7: 1797
}, pt = 589, dt = {
_0x5bca3c: 1784
}, ft = 4, gt = {
_0x2da315: 1062
}, _t = {
_0x3e7350: 542
}, ht = 95, mt = 42, vt = 237, yt = 406, bt = 680, wt = 512, xt = 418, St = 392, Tt = 387, Et = 232, kt = 557,
It = 648, At = 510, Lt = 473, Ct = 262, Ot = 424, Mt = 492, Nt = 472, Rt = 322, jt = 424, Ft = 304, Pt = 611,
Dt = 694, Bt = 675, Ut = 656, Wt = 533, Ht = 378, Gt = 333, zt = 613, Vt = 233, qt = 388, $t = 601, Zt = 328,
Yt = 387, Xt = 287, Kt = 452, Jt = 299, Qt = {
_0x5d6943: 887
}, er = {
DHRxo: tr(1389, 1354) + tr(1304, r) + tr(n, o),
CqXUt: function (e, t) {
return e === t
},
HmJqM: tr(i, 1153) + tr(a, s) + "]",
mGSUH: function (e, t) {
return e(t)
},
UwMzm: function (e, t) {
return e(t)
},
JaEDl: tr(u, l) + tr(1174, c) + tr(p, d) + tr(f, 1250) + tr(g, 1304) + tr(_, 1046) + tr(h, m) + tr(v, y) + tr(b, w) + "m3",
BNNkj: function (e, t) {
return e !== t
},
kWkAs: tr(1222, x) + "ed",
Wtufd: tr(S, T),
pAcHu: function (e, t) {
return e > t
},
OuLiI: function (e, t) {
return e >> t
},
yorHN: function (e, t) {
return e | t
},
hUrFi: function (e, t) {
return e & t
},
NSdLD: tr(E, k) + tr(I, 1188) + tr(A, A),
jqygD: function (e, t) {
return e + t
},
KfSXq: function (e, t) {
return e(t)
},
uCZiA: function (e, t) {
return e << t
},
lhaKM: function (e, t) {
return e >> t
}
};
function tr(e, t) {
return a0_0x1c067e(e, t - Qt._0x5d6943)
}
for (var rr = er[tr(L, C)][tr(O, M)]("|"), nr = 0; ;) {
switch (rr[nr++]) {
case "0":
var or = (new Date)[tr(N, R)]();
continue;
case "1":
var ir = er[tr(j, F)](Object[tr(P, D) + "pe"][tr(B, 1258) + "g"][tr(d, 1166)](t), er[tr(1218, 1083)]) || Object[tr(1106, D) + "pe"][tr(U, W) + "g"][tr(1050, H)](t) === tr(k, G) + tr(z, V);
continue;
case "2":
console.log([or, ur, e, ir ? JSON[tr(1339, 1321) + "fy"](t) : ""][tr(Z, Y)](""))
return xsCommon({
"X-s": er[tr(q, 1064)](ar, md5([or, ur, e, ir ? JSON[tr(1339, 1321) + "fy"](t) : ""][tr(Z, Y)](""))),
"X-t": or,
"x-b3-traceid": xb(),
});
case "3":
var ar = function (e) {
var t, r, n, o, i, a, s, u = {
_0x34a3a7: 1717
}, l = "", c = 0;
function p(e, t) {
return tr(e, t - -u._0x34a3a7)
}
for (e = cr(e); c < e[p(-vt, -yt)];) for (var d = lr[p(-bt, -wt)][p(-453, -xt)]("|"), f = 0; ;) {
switch (d[f++]) {
case "0":
r = e[p(-St, -Tt) + p(-Et, -333)](c++);
continue;
case "1":
l = lr[p(-kt, -648)](lr[p(-659, -It)](lr[p(-At, -573)](lr[p(-Lt, -448)](l, sr[p(-Ct, -Ot)](o)), sr[p(-Mt, -Ot)](i)), sr[p(-Nt, -424)](a)), sr[p(-Rt, -jt)](s));
continue;
case "2":
lr[p(-143, -Ft)](isNaN, r) ? a = s = 64 : isNaN(n) && (s = 64);
continue;
case "3":
a = lr[p(-Pt, -492)](lr[p(-Dt, -Bt)](15 & r, 2), lr[p(-670, -Ut)](n, 6));
continue;
case "4":
n = e[p(-Wt, -387) + p(-Ht, -Gt)](c++);
continue;
case "5":
i = lr[p(-zt, -Mt)](lr[p(-Vt, -qt)](t, 3) << 4, lr[p(-659, -$t)](r, 4));
continue;
case "6":
s = lr[p(-Zt, -qt)](n, 63);
continue;
case "7":
t = e[p(-340, -Yt) + p(-Xt, -Gt)](c++);
continue;
case "8":
o = lr[p(-Kt, -Jt)](t, 2);
continue
}
break
}
return l
};
continue;
case "4":
var sr = er[tr(X, K)];
continue;
case "5":
var ur = tr(J, Q);
continue;
case "6":
er[tr(ee, te)](typeof (pr), er[tr(re, 1357)]) && pr && (ur = er[tr(ue, le)]);
continue;
case "7":
var lr = {
iHGXU: function (e, t) {
return e < t
}, tGVtM: function (e, t) {
var r, n;
return er[(r = -ht, n = -mt, tr(n, r - -{
_0x28a46d: 1372
}._0x28a46d))](e, t)
}, ATZxG: function (e, t) {
return er[(r = 700, n = 708, tr(n, r - -_t._0x3e7350))](e, t);
var r, n
}, TChyc: function (e, t) {
return er[(r = -ft, n = -71, tr(n, r - -gt._0x2da315))](e, t);
var r, n
}, uHbbS: function (e, t) {
return er[(r = -pt, n = -726, tr(r, n - -dt._0x5bca3c))](e, t);
var r, n
}, meCkq: function (e, t) {
return er[(r = -ut, n = -lt, tr(r, n - -ct._0x48dbd7))](e, t);
var r, n
}, XXfWd: function (e, t) {
var r, n;
return er[(r = -st, n = -147, tr(r, n - -{
_0x4b47d5: 1532
}._0x4b47d5))](e, t)
}, ZOSrq: er[tr(ce, 1167)], OJhSe: function (e, t) {
return e + t
}, jnIxo: function (e, t) {
var r, n;
return er[(r = -262, n = -at, tr(r, n - -{
_0x3c5d56: 1795
}._0x3c5d56))](e, t)
}, KkKmK: function (e, t) {
return e + t
}, qYERR: function (e, t) {
return er[(r = -ot, n = -it, tr(r, n - -1814))](e, t);
var r, n
}, mRVAd: function (e, t) {
return er[(r = rt, n = nt, tr(n, r - -547))](e, t);
var r, n
}, VVsQe: function (e, t) {
var r, n;
return er[(r = et, n = tt, tr(n, r - -{
_0x1b76a5: 244
}._0x1b76a5))](e, t)
}, oOgbT: function (e, t) {
return er[(r = Je, n = 323, tr(n, r - -Qe._0x506874))](e, t);
var r, n
}, sXsJv: function (e, t) {
return er[(r = Ke, n = 1294, tr(r, n - 39))](e, t);
var r, n
}
};
continue;
case "8":
var cr = function (e) {
function t(e, t) {
return tr(e, t - -255)
}
e = e[t(ge, _e)](/\r\n/g, "\n");
for (var r = "", n = 0; lr[t(he, me)](n, e[t(939, ve)]); n++) {
var o = e[t(991, ye) + t(be, we)](n);
lr[t(xe, 1101)](o, 128) ? r += String[t(Se, 896) + t(Te, 1116)](o) : lr[t(Ee, 1159)](o, 127) && lr[t(ke, Ie)](o, 2048) ? (r += String[t(Ae, 896) + t(Le, 1116)](192 | lr[t(Ce, Oe)](o, 6)), r += String[t(Me, Ne) + t(976, Re)](lr[t(je, 1157)](63 & o, 128))) : (r += String[t(945, Ne) + t(Fe, Pe)](lr[t(964, 970)](lr[t(De, Be)](o, 12), 224)), r += String[t(Ue, We) + t(949, Pe)](lr[t(He, Ge)](63 & lr[t(ze, Be)](o, 6), 128)), r += String[t(Ve, We) + t(qe, $e)](lr[t(Ze, 970)](lr[t(Ye, Xe)](o, 63), 128)))
}
return r
};
continue;
case "9":
var pr = window;
continue
}
break
}
}
function a0_0x5097() {
var e = ["nycWN", "fBJaq", "pow", "dECQY", "brgRY", "fClZf", "UJKxX", "pAcHu", "gcTiB", "EibBa", "GiJLF", "indexOf", "Words", "roperty", "gtesd", "YAvhO", "uaTJy", "Ugvyt", "JaEDl", "constru", "xadMe", "gidcC", "ctor", "charAt", "KGFES", "xjAOo", "Hex", "eCbBW", "fucJw", "split", "Pdexl", "ize", "GdPGM", "oNewH", "cVte9UJ", "_blocks", "14966870kXTpQk", "HMSmu", "SlDup", "35asELIN", "LNqaV", "length", "MbOZq", "ytUsI", "kEGcf", "string", "iZBTs", "x3VT16I", "zSjVL", "isArray", "8757576cFFswU", "stringi", "Alblh", " argume", "rPTzg", "GRgKP", "_digest", "Vjsgx", "pZhfi", "XXfWd", "charCod", "iyFCO", "vqpTk", "gpiIM", "VOZSK", "Gbjkt", "ChEYd", "hasOwnP", "qrstuvw", "txUIa", "jqygD", "vtBnn", "JQyKB", "pGzZe", "Xcfoz", "undefin", "BNNkj", "1|0|7|2", "uCZiA", "NpxBb", "pngG8yJ", "cdefghi", "OCzab", "Asupw", "7|8|4|3", "userAge", "iHGXU", "kWkAs", "zBTXU", "pPIcF", "sPNYB", "Axxut", "syFMl", "wOcza/L", "qBlJA", "Bytes", "u5wPHsO", "vAcUW", "SAYdI", "AevWy", "CqXUt", "rCode", "BOXTR", "HjkFq", "VGCLi", "defineP", "|5|6|3|", "_hh", "QtqRk", "GDjbo", "LpfE8xz", "mzELq", "YUdCa", "LrNhj", "eAt", "hUrFi", "LRJIv", "YOTgx", "UwMzm", "SGEoV", "VlKyi", "dFaeI", "smSbR", "acefy", "rWSVh", "iAAzz", "rCZEF", "sJufA", "bARKw", "OBWNt", "RQuLg", "ZssVe", "qLlYz", "functio", "xyz0123", "WEZFu", "kdRgi", "ngGUy", "XOwwQ", "oiINe", "iZrOI", "q42KWYj", "TChyc", "qYERR", "tGVtM", "bytesTo", "Cvkcz", "wordsTo", "sXsJv", "WPwRF", "Ydsdf", "asBytes", "XTquD", "atLE", "String", "uCHFn", "oHQtNP+", "mRVAd", "ajBaX", "rOutJ", "lUeJv", "Bvk6/7=", "ILdEF", "BRIIp", "HIJKLMN", "utf8", "QgOwN", "ZhKyU", "CXKdV", "oSnIq", "bin", "jEtCt", "ctMjx", "yorHN", "FmFGF", "LObKZ", "VVsQe", "3|1|0|2", "SxoCl", "mGSUH", "ujgcs", "meCkq", "test", "THVpX", "OJhSe", "__esMod", "JiXCg", "WsrUX", "hDlaO", "uhxol", "KEclk", "OPQRSTU", "IoIff", "MFOHZ", "KGMEa", "QcSeM", "wxrWR", " Object", "HmJqM", "6|1|2", "iZCiJ", "537066GzIWAz", "3YQBOGX", "GMZot", "xabrg", "VhPab", "default", "replace", "xDRoF", "ayceF", "neANJ", "algGi", "nfQYl", "yRnhISG", "xkepE", "njmpc", "aqLvD", "binary", "asStrin", "WTFnk", "TQSsj", "IizcR", "AONgn", "Ctpkr", "fROcm", "xErjG", "enumera", "SMfox", "mirgV", "get", "cPxnB", "oOgbT", "MioMo", "PcQaQ", "bmPfU", "aJAma", "SDOEc", "size", "exports", "FVPyf", "LLELe", "UapDn", "RULwT", "drKZN", "XeGbE", "zKtsm", "rable", "configu", "gYuNh", "iamspam", "CbNCa", "JavIt", "wPNZj", "ule", "sdBkU", "jklmnop", "VWXYZab", "72vHOLBZ", "lEjNS", "jnIxo", "random", "OtvEl", "RcYBC", "5680808dJjDMI", "floor", "LzSSD", "fromCha", "YrybV", "[object", "nt ", "DeUpD", "Eexws", "zVPnW", "vkHWF", "eVqMt", "stringT", "gEtOI", "nWDjb", "0XTdDgM", "NaRii", "UXuhn", "call", "NSdLD", "_isBuff", "_ii", "cQiTj", "rChVl", "0DSfdik", "substr", "MHWER", "TgTiy", "isBuffe", "FGhlL", "kIpfS", "DHRxo", "KblCWi+", "ahCNw", "YDcuy", "ZsoFO", "FURxZ", "navigat", "readFlo", "MuVOA", "|5|3|6|", "onNTY", "KfSXq", "ykUYK", "alert", "hIvDR", "IcWsv", "slice", "zPQAv", "XhFCe", "ATZxG", "_gg", "YspuS", "710576pFMaub", "Wtufd", "HODYy", "xIXZH", "ZOSrq", "nQish", "IZpjq", "qsgOd", "wTBzw", "A4NjFqY", "2830257uUWlJW", "FXEkz", "vQXZg", "2|1", "RXkSp", "aizqT", "pykIq", "push", "jbfaq", "sTukA", "ABCDEFG", "Mhhvz", "encodin", "eyEfZ", "uHbbS", "318392HzacAI", "Kollm", "getTime", "auVzO", "oBytes", "ipvBe", "_ff", "lfrDh", " Array]", "456789+", "7|0|4|8", "Dhtnc", "prototy", "endian", "HXSVO", "VNtTi", "OuLiI", "osPAz", "RsApU", "lhedX", "CCGqR", "hECvuRX", "dBKeY", "OedFd", "a2r1ZQo", "Swqax", "join", "sBxaW", "Illegal", "lhaKM", "RSJZn", "ble", "toStrin", "|5|0|9|", "WYXEL", "IAMBz", "ZmserbB", "jAxTm", "lUAFM97", "sFtyC", "hEssz", "rotl", "QTeUD", "KkKmK"];
return (a0_0x5097 = function () {
return e
})()
}
var sessionStorage = {'sc': '5'}
function xsCommon(r) {
var u = r["X-t"] || "", l = r["X-s"] || "", c = '', p = getSigCount(u && l || c),
d = 'I38rHdgsjopgIvesdVwgIC+oIELmBZ5e3VwXLgFTIxS3bqwErFeexd0ekncAzMFYnqthIhJeDBMDKutRI3KsYorWHPtGrbV0P9WfIi/eWc6eYqtyQApPI37ekmR1QL+5Ii6sdnosjoT5yqtXqqwYrBqoIx++GDi/sVtkIx0sxuwr4qtiIkrwIi/skcc3ICLfI3Oe0utl20DZsL5eDSJejVw0IieexVwL+PtorqthPlAeVlG/IvDDIhqTgVwOJqtuIxEcZSgeVut9IvveVVtZIklKIk8rg/0sYUq6re5ejVtzoS5sScrWzd5eSWcPIx5eDutzIENeDqt7oliMtfHGIxoeTuwlnm3exdEPIkWOIiHmqs8DICDq+FVoIiciePt5ICZh4BNsDpKexqtAI3Asjg7sWc==',
f = '1', g = {
s0: 5,
s1: "",
x0: f,
x1: "3.2.0",
x2: 'Windows' || "PC",
x3: "xhs-pc-web",
x4: "2.0.5",
x5: '1871740ad70ubtbwql0r8ts34m8b8d2dghqryhxrk50000400735',
x6: u,
x7: l,
x8: d,
x9: mcr(u + l + d),
x10: p
};
r["X-S-Common"] = b64Encode(encodeUtf8(JSON.stringify(g)))
return r
}
function getSigCount(e) {
var t = Number(sessionStorage['sc']) || 0;
return e && (t++, sessionStorage['sc'] = t.toString()), t
}
console.log(sign('/api/sns/web/v1/feed', {source_note_id: '64806d79000000000800c57e'}));

View File

@ -1,14 +0,0 @@
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjA0NzRjMzEyNjBmMmY1ODQ4OTFkZGI4Yzc1MGQyMzY1NjBlMzRkOGYxNGM1MDJiNzc5NTEwOWYwZmFmOTc2OGJkODUyNzU0ZjE5ZTNlZmQ3NDA3MGZlMzIyZmFmMjAwO GM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ GFjNDg5YjlkYThjZTVlNDh mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj UzZjNkNmZjMzUyZmVhYTI2MzFmY2I2M2I0ZTdmMTJlNiJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjQwNWZkN2I1NWNiOGVlOTkyZDA2N2FlMTNiY2VlNjA3NzllZGJiZjlhMTc3NTFjZDQ0NzY5YzA3OWMyNmE0ZWFmYjNiNzk5MTkxZmViNDA3YWQ2MzlmMzYwZDYxMmZjN GM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ GFjNDg5YjlkYThjZTVlNDh mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj U1ZjM1YzFlM2Q0NmUwY2UwYjU5Yjg3NTQ2YjNhY2U4YiJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjhlODAwMjc5NDQzZTBiNjA5ZGNkMmIyMTkwMzBhNGJkNmQ5NzZjOTUzYzQ3NjZiNDBjMjVjZmYwYzY3MzcxZmI2MjZkYzk5YjkzMWE2ZGE3MzM1NWU0ZjM5ODA5MDdiM TI3NzcwNWVhOWY0YWJkMzY wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ GFjNDg5YjlkYThjZTVlNDh mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj VjNGU0ZTQ0ZTIyZTBmZjRlZGIxNWQzYzMyNjUzYjM2YyJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjhlODAwMjc5NDQzZTBiNjA5ZGNkMmIyMTkwMzBhNGJkNmQ5NzZjOTUzYzQ3NjZiNDBjMjVjZmYwYzY3MzcxZmI2MjZkYzk5YjkzMWE2ZGE3MzM1NWU0ZjM5ODA5MDdiM WM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ GFjNDg5YjlkYThjZTVlNDh mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj U4NjAwNDc3ODk4MWNmNWIwMTBhNTcwYmIyMzEwYWNiZCJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjhlODAwMjc5NDQzZTBiNjA5ZGNkMmIyMTkwMzBhNGJkNmQ5NzZjOTUzYzQ3NjZiNDBjMjVjZmYwYzY3MzcxZmI2MjZkYzk5YjkzMWE2ZGE3MzM1NWU0ZjM5ODA5MDdiM WM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ DRhMzMyNDY4MDY0YThmNWN mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj UxNzEyZjVhMTY3M2Q2NzEzNTgwYzZmNTgyODU0YTQ2NiJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjhlODAwMjc5NDQzZTBiNjA5ZGNkMmIyMTkwMzBhNGJkNmQ5NzZjOTUzYzQ3NjZiNDBjMjVjZmYwYzY3MzcxZmI2MjZkYzk5YjkzMWE2ZGE3MzM1NWU0ZjM5ODA5MDdiM WM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ DMxZWY1YjU3MWYwZjhmYzd mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMj U0OGRhMTQ1Mjc2MDZhNzIzY2YzYTA3M2ZjNmI5OTEyYSJ9
XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6 IjhlODAwMjc5NDQzZTBiNjA5ZGNkMmIyMTkwMzBhNGJkNmQ5NzZjOTUzYzQ3NjZiNDBjMjVjZmYwYzY3MzcxZmI2MjZkYzk5YjkzMWE2ZGE3MzM1NWU0ZjM5ODA5MDdiM WM5ZTNiZmRhMWZhYTFlYjk wZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZ DRhMzMyNDY4MDY0YThmNWN mNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNWVkY2ZjNmQ0ZjY4MzY4NjBkM2NmMDNkYmVmMmZhMTA3MDE5YjJjY2Q0ZTY2OTc2NTA2ODdhMTA4N2NiOTdkOGNlY2U5NTdjNzVjOTA1ZjQzYTA3NDlhNmI5ZTEyYmM3NmI1ZmRkNjY0ZmU2N2IyN2ZmMzUwZjkwZWM0MmY1NmM3ZDEzN2E2NGFhZWJlYmE4YmJmMjcwZGE5ODBiMTRhMjVjMTM2MDI2NDJhMWQ5ZjgxYzI1ODdlMmI3ZGUyOWI3MyJ9

File diff suppressed because one or more lines are too long