Skip to content
Advanced / 1 min read

在 Linux 上使用 ChangeMyIP:高级分国家排名跟踪流水线

在 Linux 上构建一个按计划运行的、分市场的排名检查流水线,轮换 ChangeMyIP 出口 IP,在每次检查时验证出口国家,并记录可进行差异对比且值得信赖的结果。

Linux HTTP(S) SEO 监测 其他

概述

排名跟踪的可信度取决于你查询时所使用的 IP。

当多市场项目中的每次检查都通过同一个地址发出时,搜索和分析端点可能返回缓存、个性化或限流的响应,而你报告的数字将不再反映本地访客实际看到的内容。

本教程构建一个高级的、按计划运行的 Linux 排名检查流水线,按市场使用 ChangeMyIP 出口 IP。你将:

  • 在每批之前确认代理端点和出口身份,
  • 通过 HTTP/HTTPS 或 SOCKS5 发送请求,并处理重试、抖动和超时,
  • 拒绝未从预期国家出口的响应,
  • 将结果追加到可进行差异对比的 JSONL 日志,并使用 cron 安排任务,
  • 将凭据保存在脚本之外,并排除在版本控制之外。

ChangeMyIP 通过 HTTP、SOCKS5、Shadowsocks、Trojan、DNS 和 WireGuard 提供专用和共享数据中心代理以及轮换住宅代理,覆盖 40+ 国家、300+ 城市和 1000+ 子网,采用固定月费计费,这使其成为用于按市场重复爬取的实用出口层。

先决条件

  • 一台可访问外部网络的 Linux 主机(Debian/Ubuntu、Fedora 或类似系统)。
  • Python 3.9 或更高版本,并安装 requests 库。
  • 用于快速手动验证的 curl 和 jq。
  • 有效的 ChangeMyIP 订阅,以及仪表板中显示的网关主机、协议端口、用户名和密码。
  • 目标市场列表(例如 us、gb、de、jp、br)以及你要跟踪的页面。

在数据中心与住宅出口之间选择

  • 数据中心(专用或共享) — 每次检查最快且最经济的选择。将其用于高并发的次要检查、sitemap 轮询,以及结果个性化不是重点的市场。
  • 住宅(轮换) — 消费者 ISP 地址。当页面或结果集必须看起来像真正的本地访客,以及数据中心 IP 段受到质疑或被返回降级内容时,使用它。
  • 混合路由 — 将地理敏感市场通过住宅出口发送,并将长尾市场保留在数据中心。由于 ChangeMyIP 采用固定月费计费,为计划增加的流量做预算很容易。

无论你选择哪种,都要验证出口国家,而不是假设它。

步骤

1. 收集端点详细信息并安全存储

登录 ChangeMyIP 仪表板,复制网关主机、你将使用的协议端口(HTTP/HTTPS 或 SOCKS5)、用户名和密码。将它们保存在 root 可读的环境文件中,而不是放在脚本内:

sudo install -d -m 700 /etc/cmip
sudo tee /etc/cmip/env >/dev/null <<'EOF'
CMIP_HOST=gateway-host-from-dashboard
CMIP_PORT=port-from-dashboard
CMIP_USER=your-username
CMIP_PASS=your-password
CMIP_SCHEME=http
EOF
sudo chmod 600 /etc/cmip/env

当你被分配的端口使用 SOCKS5,并且你希望 DNS 在代理端而非你的主机上解析时,将 CMIP_SCHEME 设置为 socks5h。

2. 安装工具链

sudo apt update
sudo apt install -y curl jq python3 python3-pip
python3 -m pip install --user requests

3. 通过代理验证单个请求

set -a; . /etc/cmip/env; set +a

curl -sS --max-time 20 \
  --proxy "${CMIP_SCHEME}://${CMIP_USER}:${CMIP_PASS}@${CMIP_HOST}:${CMIP_PORT}" \
  https://ipinfo.io/json | jq '{ip, city, region, country, org}'

运行三到四次。在轮换套餐中,出口 IP 应在每次运行之间发生变化,并且绝不应与你自己的 ISP 地址匹配。如果输出是你自己的连接,则代理根本没有生效。

4. 在一个文件中描述你的市场和目标

{
  "markets": {
    "us": ["https://example.com/pricing"],
    "gb": ["https://example.com/pricing"],
    "de": ["https://example.com/pricing"]
  }
}

将其保存为 /etc/cmip/targets.json,并将市场代码设置为与 ChangeMyIP 仪表板中可用的国家端点匹配。

5. 编写带每次检查地理验证的流水线

#!/usr/bin/env python3
'''Per-market rank checks through ChangeMyIP rotating proxies.'''
import json
import os
import random
import time
from pathlib import Path

import requests

HOST = os.environ['CMIP_HOST']
PORT = os.environ['CMIP_PORT']
USER = os.environ['CMIP_USER']
PASS = os.environ['CMIP_PASS']
SCHEME = os.environ.get('CMIP_SCHEME', 'http')

TARGETS = json.loads(Path('/etc/cmip/targets.json').read_text())
OUT = Path('/var/log/cmip/rank-checks.jsonl')
OUT.parent.mkdir(parents=True, exist_ok=True)


def proxy_url():
    return f'{SCHEME}://{USER}:{PASS}@{HOST}:{PORT}'


def get(session, url, retries=4):
    last = None
    for attempt in range(1, retries + 1):
        try:
            resp = session.get(url, timeout=25)
            resp.raise_for_status()
            return resp.text
        except requests.RequestException as exc:
            last = exc
            time.sleep(min(2 ** attempt + random.random(), 30))
    raise last


def run():
    for market, urls in TARGETS['markets'].items():
        session = requests.Session()
        session.proxies = {'http': proxy_url(), 'https': proxy_url()}
        session.headers['User-Agent'] = (
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
            '(KHTML, like Gecko) Chrome/124.0 Safari/537.36'
        )

        try:
            geo = json.loads(get(session, 'https://ipinfo.io/json'))
            exit_country = (geo.get('country') or '').lower()
        except (requests.RequestException, json.JSONDecodeError) as exc:
            print(f'{market}: geo check failed: {exc}')
            continue

        for url in urls:
            record = {
                'ts': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
                'market': market,
                'url': url,
                'exit_ip': geo.get('ip'),
                'exit_country': exit_country,
                'country_ok': exit_country == market,
            }
            try:
                body = get(session, url)
                record['bytes'] = len(body)
                record['status'] = 'ok'
            except requests.RequestException as exc:
                record['status'] = type(exc).__name__
            with OUT.open('a') as fh:
                fh.write(json.dumps(record) + '\n')
            print(record)


if __name__ == '__main__':
    run()

将其保存为 /opt/cmip/rank_check.py。country_ok 标志是让报告保持真实可信的关键:从错误国家出口的检查仍会被记录,但你可以在下游排除它。

由于轮换套餐可能会为每个请求分配不同的出口 IP,地理检查和页面抓取可能从不同地址发出。如果你的 ChangeMyIP 仪表板提供会话或轮换控制,例如会话时长或粘性会话令牌,则为每次检查固定一个出口 IP,以便两个请求共享同一地址;否则,将 country_ok 视为该批次的强信号,而不是每次单独抓取的保证。

6. 在前台运行一次

set -a; . /etc/cmip/env; set +a
python3 /opt/cmip/rank_check.py

在安排任何任务之前检查日志:

jq -s 'group_by(.market) | map({market: .[0].market, checks: length, ok: (map(select(.country_ok)) | length)})' /var/log/cmip/rank-checks.jsonl

7. 安排任务

17 */6 * * * set -a; . /etc/cmip/env; set +a; /usr/bin/python3 /opt/cmip/rank_check.py >> /var/log/cmip/run.log 2>&1

错开分钟数,而不是所有任务都在整点运行,并使总流量与你的 ChangeMyIP 套餐所支持的规模保持一致。

8. 对历史记录进行差异对比,而不是重新读取单次运行结果

jq -r 'select(.country_ok) | [.ts, .market, .url] | @tsv' /var/log/cmip/rank-checks.jsonl | tail -n 40

验证每个市场端点的出口 IP

针对 ChangeMyIP 仪表板中显示的每个国家端点重复此代码块一次,并为每个端点导出匹配的 CMIP_SCHEME、CMIP_USER、CMIP_PASS、CMIP_HOST 和 CMIP_PORT:

set -a; . /etc/cmip/env; set +a

for attempt in 1 2 3; do
  curl -sS --max-time 20 \
    --proxy "${CMIP_SCHEME}://${CMIP_USER}:${CMIP_PASS}@${CMIP_HOST}:${CMIP_PORT}" \
    https://ipinfo.io/json | jq -r '[.country, .city, .ip, .org] | @tsv'
done

记录你实际获得的国家。这些才是你可以有信心报告的市场。

故障排除

症状 可能原因 处理方式
407 Proxy Authentication Required 凭据缺失、输入错误,或包含需要 URL 编码的字符 重新检查仪表板中的值,并在构建代理 URL 前对密码中的保留字符进行百分号编码,例如 @ 变为 %40
curl: (7) 或连接超时 端口错误,或 HTTP 端口与 SOCKS5 方案一起使用 重新复制与你所选协议匹配的端口
出口国家始终不是你要的市场 该端点或端口未应用国家定向,或轮换选择了其他区域 使用仪表板中列出的特定国家端点,并在存在该控制项时固定会话
目标站点返回 429 或 503 请求节奏过于激进 增加请求之间的延迟,加入抖动,并在计划中分散市场
TLS 握手失败 方案和端口不匹配 尝试对匹配的 SOCKS5 端口使用 socks5h 方案
行为与手动浏览器检查不同 Cookie、缓存或不同的用户代理 每个市场复用一个 requests.Session,并在多次运行之间保持标头一致
DNS 似乎在本地解析 HTTP 代理方案在你的主机上解析名称 切换到 socks5h,使查找在代理端进行
日志文件无限增长 没有轮换或保留策略 添加 logrotate,或清除早于保留窗口的条目

总结

  • 只有当你知道排名检查从哪个国家出口时,它才有效;在规模化场景下,地理验证不是可选项。
  • ChangeMyIP 的轮换住宅出口适合市场精确的检查,而专用或共享数据中心出口适合大批量工作;固定月费计费让预算保持可预测。
  • 通过为每条记录记录 country_ok 并在下游据此过滤,让流水线保持诚实可信。
  • 在信任自动化计划之前,手动验证每个国家端点,并在每次添加市场时重新运行该验证。
  • 负责任地提升强度:稳定的节奏、带抖动的重试,以及每个市场一个会话,每次都会胜过蛮力方式。