Python实战 | 如何使用海外代理IP采集 X 上不同国家的热搜

27 阅读7分钟

image-20260127093708342

一、X上的热搜话题为什么会“因国家而异”?

最近,“斩杀线”这个词在海内外社交平台上频繁出现:在部分地区,它被用来讨论游戏机制;在另一些地区,则演变成投资、体育甚至娱乐梗。这种同一关键词、不同地区讨论重点完全不同的现象,并不奇怪,本质上,是同一套内容在不同国家,被平台分发给了不同的人群。

在 X 上,这种差异最直观地体现在热搜中。

今天,我们就一起来看看,如何通过代码使用海外代理IP,来量化这些差异?

二、研究目标:用“国家出口”解释 X 热搜差异

在进入技术细节前,先明确机制:在 X 的产品逻辑中,“热搜”并不是一个全局统一的榜单,而是按地点维度独立计算的趋势集合。

从系统角度来理解,就是:

  • 平台在计算热搜时,本身就会区分你是从哪个国家访问的
  • 国家级趋势 ≠ 全球趋势
  • 不同国家之间不存在“天然同步”的假设

结论非常明确:如果不区分国家出口环境,采集到的热搜数据将缺乏明确的地区语义。在 Python 中,直接请求 API 时,不用代理的话,网站会把你的请求当成“来自你所在地区”。用海外代理后,我们可以更接近“从目标国家访问”的效果,结果也更容易对比。

image-20260127094318977

三、网页分析:X 热搜数据是如何被加载的?

在真正开始采集之前,首先需要回答一个问题:X 的热搜数据,是直接写在网页 HTML 里的吗?

在日常工作中,你可能习惯用 BeautifulSoup 或 Selenium 解析网页,但这里我们先通过手动分析理解数据加载逻辑,避免后期debug时一头雾水。

3.1 页面结构分析

打开浏览器开发者工具(F12)→ Network → 选 Fetch/XHR → 刷新页面。

image-20260127101216612

按 F5 刷新 X 的探索页面,观察 Network 面板中冒出来的请求列表,点击一个名字带 “trends” 或 “explore” 的端点:

image-20260127102936771

image-20260127103318571

切换到 Response 标签查看返回体。你会看到结构化数据,通常是 JSON 格式。

通过浏览器访问 X 的热搜页面,可以发现:

  • 初始 HTML 内容极少,基本就是个 skeleton。
  • 页面加载完成后,热搜内容才逐步出现。

这意味着:热搜数据并非静态页面内容,而是由前端异步拉取并渲染的。

3.2 技术路线选择:网页分析 + api接口

在理解网页结构后,我发现,最好还是不要直接模拟网页请求进行大规模抓取,原因很明确:

  • 页面接口不稳定,迭代频繁
  • 请求参数复杂,不适合长期维护
  • 不利于规模化和合规使用

因此,最终的数据采集阶段,采用 X 官方趋势接口(Twitter API v1.1 或 v2 的 /trends/place.json)。

四、实操:使用海外代理IP采集不同国家热搜

4.1 为什么需要海外代理 IP?

在这个场景中,海外代理IP的作用不是“访问 X”,而是:

  • 构建不同国家的网络出口环境。
  • 控制“请求来自哪个国家”这一实验变量。
  • 保证多国家趋势采集的一致性与可复现性。

换句话说:海外代理IP是趋势研究中的“实验环境控制工具”。在 Python 中,通过 proxies 参数,你可以轻松集成代理到 requests 请求中,避免因为请求太集中,导致访问失败。

image-20260127104144638

获取海外代理IP后,你就可以使用了:

import requests

# ===== 1. 获取代理IP =====
def get_proxy():
    proxy_url = "https://overseas.proxy.qg.net/get?key=yourkey&num=1&area=&isp=&format=txt&seq=&distinct=false"
    
    try:
        resp = requests.get(proxy_url, timeout=10)
        proxy_ip = resp.text.strip()
        print("获取到代理IP:", proxy_ip)
        return proxy_ip
    except Exception as e:
        print("获取代理失败:", e)
        return None


# ===== 2. 测试代理是否可用 =====
def test_proxy(proxy_ip):
    proxies = {
        "http": f"http://{proxy_ip}",
        "https": f"http://{proxy_ip}"
    }

    # 用于测试的外网 IP 查询接口
    test_url = "https://httpbin.org/ip"

    try:
        resp = requests.get(test_url, proxies=proxies, timeout=10)
        print("请求状态码:", resp.status_code)
        print("返回内容:", resp.text)
        print("✅ 代理可用")
    except Exception as e:
        print("❌ 代理不可用:", e)


# ===== 3. 主程序 =====
if __name__ == "__main__":
    proxy = get_proxy()
    if proxy:
        test_proxy(proxy)

4.3 数据采集流程

完整流程如下:

选择目标国家
   ↓
配置对应国家的海外代理 IP
   ↓
请求 X 官方趋势接口(国家级)
   ↓
获取热搜列表(关键词 / 排名 / 热度)
   ↓
统一时间戳存储

这里需要强调:

  • 数据来源为 X 官方趋势接口(需申请 Twitter Developer API 访问,获取 Bearer Token)。
  • 代理IP仅用于网络出口控制。
  • 不涉及账号操作或用户行为模拟(纯 API call,无需 fake user agent)。

安装 requests(标准库),并有 Twitter API Bearer Token即可开始上手了。

WOEID 可从 /trends/available.json 获取(例如,美国:23424977,日本:23424856)。

import requests
import json
from datetime import datetime

# 1) 基本参数
BEARER_TOKEN = "你的 X API Bearer Token"  # 需要你自己申请
WOEIDS = {
    "USA": 23424977,
    "Japan": 23424856,
}

# 2) 动态获取青果网络海外代理ip(参数是代理返回时的分隔符,对采集逻辑无影响,保持默认即可)
QG_PROXY_API = "https://overseas.proxy.qg.net/get?key=yourkey&num=1&area=&isp=&format=txt&seq=\r\n&distinct=false"

def fetch_proxy_from_qg() -> str:
    """从青果接口取一个代理,返回 'ip:port' 字符串。"""
    r = requests.get(QG_PROXY_API, timeout=10)
    r.raise_for_status()
    proxy = r.text.strip()
    if not proxy or ":" not in proxy:
        raise ValueError(f"代理返回异常:{r.text!r}")
    return proxy

def get_trends_for_country(woeid: int, proxy_ip_port: str):
    """通过代理请求 X 趋势接口,返回趋势列表(trends)。"""
    url = f"https://api.twitter.com/1.1/trends/place.json?id={woeid}"
    headers = {"Authorization": f"Bearer {BEARER_TOKEN}"}

    proxies = {
        "http": f"http://{proxy_ip_port}",
        "https": f"http://{proxy_ip_port}",
    }

    resp = requests.get(url, headers=headers, proxies=proxies, timeout=20)
    resp.raise_for_status()
    data = resp.json()
    return data[0]["trends"]

def main():
    results = {}
    timestamp = datetime.utcnow().isoformat()

    # 每个国家采集时各取一个代理
    for country, woeid in WOEIDS.items():
        try:
            proxy = fetch_proxy_from_qg()
            trends = get_trends_for_country(woeid, proxy)
            results[country] = {
                "timestamp": timestamp,
                "proxy_used": proxy,  # 可选:记录本次用到的代理,便于排查
                "trends": trends[:10],
            }
            print(f"[OK] {country} 采集成功(proxy={proxy})")
        except Exception as e:
            print(f"[FAIL] {country} 采集失败:{e}")

    with open("trends_data.json", "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=2)

if __name__ == "__main__":
    main()

image-20260127111711104

五、数据分析:如何比较不同国家的热搜差异?

为了系统刻画国家间热搜差异,本文从三个维度进行分析。作为 Python 使用者,你可以用 Pandas 处理采集的数据。

5.1 内容相似度:热搜重合度

分析方法:

  • 取各国家 Top N 热搜关键词。
  • 计算国家之间的关键词重合比例(使用集合交集,O(1) lookup)。

意义:

  • 重合度高:全球性事件 / 热点。
  • 重合度低:地区性议题占主导。

Python 示例:

import pandas as pd

# 假设 results 来自采集
df_usa = pd.DataFrame(results['USA']['trends'])['name']
df_japan = pd.DataFrame(results['Japan']['trends'])['name']

intersection = set(df_usa) & set(df_japan)
overlap_ratio = len(intersection) / min(len(df_usa), len(df_japan))
print(f"重合度: {overlap_ratio:.2%} - 如果低,说明 localization strong")

5.2 地区特性:本地化比例

分析方法:

  • 判断热搜是否包含本地语言、本地实体或地区事件(可使用 NLP 库如 spaCy,entity recognition 出本地实体)。
  • 统计本地化话题占比。

5.3 传播强度:热度分布特征

分析方法:

  • 分析 tweet_volume 的分布(使用 NumPy 计算标准差,check outlier)。
  • 对比不同国家热搜的“头部集中度”(例如,Top 1 热度 / 总热度)。

意义:

  • 某些国家呈现“强头部效应”。
  • 某些国家话题更分散、多样。

Python 示例:

import numpy as np

volumes_usa = pd.DataFrame(results['USA']['trends'])['tweet_volume'].dropna().values
head_concentration = volumes_usa[0] / np.sum(volumes_usa)
print(f"USA 头部集中度: {head_concentration:.2%} - Pareto principle in action?")

六、结论

从网页分析到代理出口控制,再到趋势数据对比,本质上是在做一件事:让“地区”成为一个可被精确控制和分析的变量。这不仅适用于 X,也适用于所有内容分发高度依赖地域的平台,比如还可以直接应用于:

  • 海外舆情监控
  • 跨区域内容运营
  • 国际品牌市场洞察
  • 品牌广告投放效果