Created
March 8, 2026 09:43
-
-
Save discountry/7d1d0497303d0c440fcfb172c3f2b428 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ================= 1. 用户自定义配置 (请修改此处) ================= | |
| # [必填] 推特用户名 (不需要加 @,例如 elonmusk) | |
| TWITTER_USER="discountifu" | |
| # [必填] 币安广场 API Key | |
| BINANCE_API_KEY="123123123" | |
| # [可选] 币安广场 API URL (通常不需要修改) | |
| BINANCE_API_URL="https://www.binance.com/bapi/composite/v1/public/pgc/openApi/content/add" | |
| # [可选] 工作目录 (日志和临时文件存放位置) | |
| WORK_DIR="$HOME/binance_sync" | |
| # ================= 2. 高级系统配置 (通常不需要修改) ================= | |
| # Nitter 实例域名列表 | |
| # 脚本会自动将用户名拼接到这些域名后面 | |
| # 建议多保留几个,因为 Nitter 实例经常挂 | |
| NITTER_DOMAINS=( | |
| "https://nitter.net" | |
| "https://nitter.privacydev.net" | |
| ) | |
| # 保留历史记录行数 (建议调大,防止 --full 模式下历史记录被过快滚动覆盖) | |
| KEEP_HISTORY_COUNT=200 | |
| # 网络请求配置 | |
| RETRY_INTERVAL=3 # 重试间隔(秒) | |
| MAX_RETRIES=3 # 单个源最大重试次数 | |
| TIMEOUT=15 # 连接超时时间(秒) | |
| # ================================================================= | |
| # --- 参数解析 --- | |
| # 默认模式: today (仅同步今日) | |
| # 参数 --full: full (同步所有 RSS 内容) | |
| SYNC_MODE="today" | |
| if [[ "$1" == "--full" ]]; then | |
| SYNC_MODE="full" | |
| fi | |
| # --- 基础环境准备 --- | |
| HISTORY_FILE="$WORK_DIR/history.log" | |
| TEMP_XML="$WORK_DIR/rss_feed.xml" | |
| mkdir -p "$WORK_DIR" | |
| touch "$HISTORY_FILE" | |
| # 日志函数 | |
| log() { | |
| echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | |
| } | |
| # --- 检查配置完整性 --- | |
| if [ -z "$TWITTER_USER" ] || [ -z "$BINANCE_API_KEY" ]; then | |
| log "错误: 请先在脚本顶部配置 TWITTER_USER 和 BINANCE_API_KEY" | |
| exit 1 | |
| fi | |
| # 获取今日日期 (UTC),RSS 通常使用 GMT/UTC | |
| TODAY_DATE=$(date -u +%Y-%m-%d) | |
| log "========================================" | |
| log "任务开始: 同步 @$TWITTER_USER 的推文" | |
| if [ "$SYNC_MODE" == "full" ]; then | |
| log "运行模式: [全量同步] (同步所有未记录的推文)" | |
| else | |
| log "运行模式: [仅今日] (仅同步 UTC 日期为 $TODAY_DATE 的推文)" | |
| fi | |
| # 检查依赖 | |
| for cmd in xmlstarlet jq curl; do | |
| if ! command -v $cmd &> /dev/null; then | |
| log "错误: 未安装 $cmd,请运行 sudo apt-get install $cmd" | |
| exit 1 | |
| fi | |
| done | |
| # ================= 下载模块 ================= | |
| DOWNLOAD_SUCCESS=false | |
| # 遍历 Nitter 域名列表,自动拼接 RSS URL | |
| for domain in "${NITTER_DOMAINS[@]}"; do | |
| # 移除域名末尾可能存在的斜杠,构建最终 URL | |
| domain=${domain%/} | |
| url="$domain/$TWITTER_USER/rss" | |
| log "尝试从源获取数据: $url" | |
| for (( attempt=1; attempt<=MAX_RETRIES; attempt++ )); do | |
| http_code=$(curl -s -L --connect-timeout "$TIMEOUT" \ | |
| -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" \ | |
| -w "%{http_code}" -o "$TEMP_XML" "$url") | |
| # 检查 HTTP 200 且文件内容有效 | |
| if [ "$http_code" == "200" ] && [ -s "$TEMP_XML" ]; then | |
| if grep -q "<?xml" "$TEMP_XML" || grep -q "<rss" "$TEMP_XML"; then | |
| log "下载成功 (第 $attempt 次尝试)" | |
| DOWNLOAD_SUCCESS=true | |
| break 2 # 跳出两层循环 | |
| else | |
| log "警告: 下载内容不是有效的 XML (第 $attempt 次尝试)" | |
| fi | |
| else | |
| log "请求失败 (HTTP $http_code) - 第 $attempt/$MAX_RETRIES 次重试..." | |
| fi | |
| if [ "$attempt" -lt "$MAX_RETRIES" ]; then | |
| sleep "$RETRY_INTERVAL" | |
| fi | |
| done | |
| log "当前源不可用,切换下一个备用源..." | |
| done | |
| if [ "$DOWNLOAD_SUCCESS" = false ]; then | |
| log "错误: 所有 RSS 源均无法访问,请检查网络或 Nitter 实例状态。" | |
| exit 1 | |
| fi | |
| # ================= 解析与同步模块 ================= | |
| # 统计条目数 | |
| item_count=$(xmlstarlet sel -t -v "count(//item)" "$TEMP_XML" 2>/dev/null) | |
| if [[ -z "$item_count" || ! "$item_count" =~ ^[0-9]+$ ]]; then | |
| item_count=0 | |
| fi | |
| log "解析到 $item_count 条推文" | |
| if [ "$item_count" -eq 0 ]; then | |
| log "没有新内容。" | |
| rm -f "$TEMP_XML" | |
| exit 0 | |
| fi | |
| # 倒序处理 (从旧到新同步) | |
| for (( i=item_count; i>=1; i-- )); do | |
| # 提取 GUID, Title, PubDate | |
| guid=$(xmlstarlet sel -t -v "//item[$i]/guid" "$TEMP_XML" 2>/dev/null) | |
| content=$(xmlstarlet sel -t -v "//item[$i]/title" "$TEMP_XML" 2>/dev/null) | |
| pubDate=$(xmlstarlet sel -t -v "//item[$i]/pubDate" "$TEMP_XML" 2>/dev/null) | |
| # 空值检查 | |
| if [ -z "$guid" ] || [ -z "$content" ]; then continue; fi | |
| # 1. 查重 (历史记录中存在则跳过) | |
| if grep -q "$guid" "$HISTORY_FILE"; then | |
| continue | |
| fi | |
| # 2. 日期检查 (非 Full 模式下,非今日推文跳过) | |
| if [ "$SYNC_MODE" != "full" ]; then | |
| # 格式化 RSS 时间为 YYYY-MM-DD | |
| item_date_str=$(date -d "$pubDate" -u +%Y-%m-%d 2>/dev/null) | |
| if [ "$item_date_str" != "$TODAY_DATE" ]; then | |
| # debug log: log "跳过非今日推文: $item_date_str" | |
| continue | |
| fi | |
| fi | |
| log "正在同步推文: $guid" | |
| # 构建 JSON Payload | |
| json_payload=$(jq -n --arg txt "$content" '{bodyTextOnly: $txt}') | |
| # 调用币安 API | |
| response=$(curl -s -X POST "$BINANCE_API_URL" \ | |
| -H "X-Square-OpenAPI-Key: $BINANCE_API_KEY" \ | |
| -H "Content-Type: application/json" \ | |
| -H "clienttype: binanceSkill" \ | |
| -d "$json_payload") | |
| api_code=$(echo "$response" | jq -r '.code') | |
| if [ "$api_code" == "000000" ]; then | |
| log "同步成功! ID: $(echo "$response" | jq -r '.data.id')" | |
| # 写入历史记录 | |
| echo "$guid | $(date '+%Y-%m-%d %H:%M:%S')" >> "$HISTORY_FILE" | |
| # 滚动清理历史 (保持最后 N 行) | |
| line_count=$(wc -l < "$HISTORY_FILE") | |
| if [ "$line_count" -gt "$KEEP_HISTORY_COUNT" ]; then | |
| tail -n "$KEEP_HISTORY_COUNT" "$HISTORY_FILE" > "$HISTORY_FILE.tmp" && mv "$HISTORY_FILE.tmp" "$HISTORY_FILE" | |
| fi | |
| # 避免 API 速率限制 | |
| sleep 5 | |
| else | |
| log "同步失败. API 响应: $response" | |
| fi | |
| done | |
| # 清理临时文件 | |
| rm -f "$TEMP_XML" | |
| log "任务完成。" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
这是一个将上述脚本设置为 Ubuntu 定时任务(Crontab)的详细教程。
由于脚本已经设置了默认行为(只同步今日推文),非常适合设置为高频运行的定时任务。
步骤 1:准备工作
在设置定时任务之前,必须确保脚本有执行权限,并且你需要知道脚本的绝对路径。
假设你的脚本名为
binance_sync.sh。运行以下命令并记下输出的路径:
realpath binance_sync.sh # 输出示例: /home/ubuntu/binance_sync.sh步骤 2:编辑 Crontab 配置
Ubuntu 使用
crontab命令来管理定时任务。在终端输入:
(如果是第一次运行,系统会让你选择编辑器,输入
1选择 nano 即可,最简单易用)。2. 理解 Cron 语法:
Cron 表达式由 5 个时间字段和一个命令组成。
格式如下:
步骤 3:添加定时任务
在打开的编辑器文件末尾,添加你需要的计划任务。由于 Nitter 实例有时不稳定,且为了及时获取推文,建议每 30分钟 或 1小时 运行一次。
方案 A:每 30 分钟运行一次 (推荐)
将
/home/ubuntu/binance_sync.sh替换为你步骤 1中获取的真实路径。方案 B:每 1 小时运行一次 (整点)
关于命令末尾的解释:
>> /home/ubuntu/cron_run.log:这会将脚本的标准输出(例如脚本里的echo)追加保存到一个日志文件中,方便你排查脚本是否运行了。2>&1:这会将错误信息(比如 curl 报错)也重定向到同一个日志文件中。步骤 4:保存并退出
如果你使用的是 nano 编辑器:
Ctrl + O(保存)。Enter(确认文件名)。Ctrl + X(退出编辑器)。系统会提示
crontab: installing new crontab,表示设置成功。步骤 5:验证与排查 (重要)
Cron 任务是在后台静默运行的,如果不检查,你可能不知道它是否在工作。
确保任务确实存在。
查看系统是否触发了该任务。
如果你看到类似
(root) CMD (/home/ubuntu/binance_sync.sh ...)的记录,说明系统尝试执行了。3. 常见问题:找不到命令 (Command not found)
Cron 的环境变量(PATH)通常比用户登录时要少。如果脚本手动运行正常,但 Cron 运行报错说找不到
jq或xmlstarlet,有两种解决方法:方法一(推荐):在脚本内部指定绝对路径
或者在脚本顶部(
#!/bin/bash下方)添加 PATH 定义:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin export PATH方法二:在 Crontab 文件顶部添加
再次运行
crontab -e,在文件最顶部添加:总结
设置完成后: