选地区
Google.de 走欧洲,Yandex 走独联体,Baidu 走中国。其余市场用全球混合,它的代理池也最大。
排名取决于查询从哪里发出。代理池首先要解决这个问题。
来自你所监测国家的地址
Resi Core:国家写在用户名中;套餐则用CSV导出中的国家列
每批查询一个新 IP
Resi Core每次请求都换地址,套餐每天更换约三分之一的地址
足够的并发,撑得起大批关键词
Resi不限线程,套餐500到5000个线程
直接配合你现有的工具
Resi用字符串中的用户名和密码授权,套餐按IP授权;A-Parser、Key Collector和Rank Tracker支持HTTP和SOCKS5
一个搜索结果页很轻,所以1GB能覆盖上千次查询。每GB价格随订单增大而降低。
| 订单大小 | Resi Core | Resi Prime |
|---|---|---|
| 1GB+ | $0.85 | $2.29 |
| 10GB+省7% | $0.79 | $2.09 |
| 50GB+ | $0.72 | $1.95 |
| 100GB+ | $0.65 | $1.75 |
| 500GB+ | $0.57 | $1.55 |
| 1000GB+ | $0.49 | $1.39 |
价格为每1GB的美元价格。按整GB购买,最少1GB。
代理池
相比1GB起的价格,您节省7%($1.50)
再加25GB,每GB就降到$0.72
购买此数量购买的GB自购买之日起3个月内可用;之后剩余的部分会被清零。
Google.de 走欧洲,Yandex 走独联体,Baidu 走中国。其余市场用全球混合,它的代理池也最大。
拿到 CSV 导出后,只保留国家列与你监测的市场一致的行;现成的生成脚本会为每个国家写出一个 ip:port 文件。
排名工具接受代理文件或 URL。把刷新间隔设为 10 分钟,列表会自动保持最新。
设置 DOMAIN 和 COUNTRY,把关键词放进 keywords.txt。脚本通过该国代理查询搜索引擎,把你的域名排名写入 CSV。请给它一个经过代理检测的干净代理池。
#!/usr/bin/env python3
"""Search-position checker for Advanced.name proxies.
Reads the CSV proxy export, keeps one country, then asks a search engine for each
keyword through a proxy from that country and reports where your domain sits in
the results. Standard library only. Edit CONFIG and run: python3 rank.py
"""
# ================================ CONFIG ====================================
CSV_URL = "https://get.advanced.name/YOUR_LIST_ID.csv" # CSV export link from your dashboard
COUNTRY = "DE" # ISO 3166-1 alpha-2: positions are read from this country
MIN_SPEED = 3 # keep proxies with speed >= this value
DOMAIN = "example.com" # the domain whose position you track
KEYWORDS_FILE = "keywords.txt" # one keyword per line
SEARCH_URL = "https://www.bing.com/search?q={q}&count=50&setlang={cc}" # {q}=keyword, {cc}=country
OUT_FILE = "positions.csv" # keyword;position;proxy is written here
TIMEOUT = 20
# ============================================================================
import csv
import io
import re
import sys
import urllib.parse
import urllib.request
COL_IP, COL_PORT, COL_COUNTRY, COL_SPEED = 0, 1, 2, 3
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0 Safari/537.36"
HREF = re.compile(r'href="https?://([^/"]+)', re.I)
def load_proxies():
raw = urllib.request.urlopen(CSV_URL, timeout=30).read().decode("utf-8", "replace")
pool = []
for row in csv.reader(io.StringIO(raw), delimiter=";"):
if len(row) <= COL_SPEED or not row[COL_PORT].strip().isdigit():
continue
if COUNTRY and row[COL_COUNTRY].strip().upper() != COUNTRY.upper():
continue
if int(row[COL_SPEED] or 0) < MIN_SPEED:
continue
pool.append(row[COL_IP].strip() + ":" + row[COL_PORT].strip())
return pool
def position(html, domain):
"""First place the domain shows up among the result links, or 0 if absent."""
rank, seen = 0, set()
for host in HREF.findall(html):
host = host.lower()
if "bing.com" in host or "microsoft.com" in host or host in seen:
continue
seen.add(host)
rank += 1
if host == domain or host.endswith("." + domain):
return rank
return 0
def main():
proxies = load_proxies()
if not proxies:
sys.exit("No proxies for COUNTRY=%r." % COUNTRY)
with open(KEYWORDS_FILE, encoding="utf-8") as fh:
keywords = [line.strip() for line in fh if line.strip()]
print("proxies: %d (%s), keywords: %d" % (len(proxies), COUNTRY, len(keywords)))
with open(OUT_FILE, "w", encoding="utf-8", newline="") as out:
writer = csv.writer(out, delimiter=";")
writer.writerow(["keyword", "position", "proxy"])
for i, keyword in enumerate(keywords):
proxy = proxies[i % len(proxies)]
url = SEARCH_URL.format(q=urllib.parse.quote(keyword), cc=COUNTRY.lower())
handler = urllib.request.ProxyHandler({"http": "http://" + proxy, "https": "http://" + proxy})
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": COUNTRY.lower()})
try:
html = urllib.request.build_opener(handler).open(req, timeout=TIMEOUT).read().decode("utf-8", "replace")
pos = position(html, DOMAIN.lower())
except Exception as exc:
pos = "err: %s" % exc.__class__.__name__
writer.writerow([keyword, pos, proxy])
print("%-40s %s" % (keyword[:40], pos))
print("written %s" % OUT_FILE)
if __name__ == "__main__":
main()
从控制面板粘贴一行Resi代理,设置DOMAIN,并把关键词放进keywords.txt。脚本通过代理在真实的Chromium中打开搜索结果,等待AI区块加载完成,然后把区块是否出现、引用了哪些域名、您的域名是否在其中写入CSV。它会自行关闭欧盟的cookie横幅,并把验证码或代理错误单独标在一行。Google会更改页面结构,所以区块标题放在LABELS中。
#!/usr/bin/env python3
"""AI Overview tracker for Advanced.name residential proxies.
Opens Google results for every keyword through a Resi Core or Resi Prime line
in a real Chromium, because the AI block is drawn by JavaScript. Records
whether the page shows the AI block and which domains it cites.
Setup: pip install playwright && python -m playwright install chromium
"""
# ================================ CONFIG ====================================
PROXY = "res.advanced.name:9000:USER-type-residential-country-us:PASS" # host:port:login:password line from your dashboard
DOMAIN = "example.com" # the domain you want to see among the cited sources
KEYWORDS_FILE = "keywords.txt" # one keyword per line
SEARCH_URL = "https://www.google.com/search?q={q}&hl={hl}&gl={gl}" # {q}=keyword
HL = "en" # interface language of the results page
GL = "us" # country of the results, keep it equal to the country in the login
LABELS = "AI Overview|AI Mode" # heading text of the AI block, separated by |
CONSENT = "Reject all|Accept all" # cookie banner buttons in EU countries, in the HL language
OUT_FILE = "ai_overview.csv" # keyword;ai_block;cited;your_domain is written here
WAIT_MS = 4000 # time for the AI block to finish drawing
HEADLESS = True # set False to watch the browser
# ============================================================================
import csv
import sys
import urllib.parse
from playwright.sync_api import sync_playwright
FIND_BLOCK = """(labels) => {
const heads = [...document.querySelectorAll('h1,h2,h3,div,span')]
.filter(e => e.children.length === 0 && labels.includes(e.textContent.trim()));
if (!heads.length) return null;
let box = heads[0];
for (let i = 0; i < 8 && box.parentElement; i++) {
box = box.parentElement;
const links = [...box.querySelectorAll('a[href^="http"]')];
if (links.length >= 2 && box.innerText.length > 200) return links.map(a => new URL(a.href).hostname);
}
return [];
}"""
def proxy_of(line):
host, port, user, password = line.strip().split(":", 3)
return {"server": "http://%s:%s" % (host, port), "username": user, "password": password}
def bare(host):
host = host.lower()
return host[4:] if host.startswith("www.") else host
def main():
keywords = [k.strip() for k in open(KEYWORDS_FILE, encoding="utf-8") if k.strip()]
labels = [x.strip() for x in LABELS.split("|") if x.strip()]
consent = [x.strip() for x in CONSENT.split("|") if x.strip()]
rows = []
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=HEADLESS, proxy=proxy_of(PROXY))
page = browser.new_page(locale=HL)
for kw in keywords:
url = SEARCH_URL.format(q=urllib.parse.quote_plus(kw), hl=HL, gl=GL)
try:
resp = page.goto(url, wait_until="domcontentloaded", timeout=60000)
if resp is None or resp.status >= 400:
status = "http %s" % (resp.status if resp else "none")
print("%-40s %s" % (kw[:40], status), file=sys.stderr)
rows.append([kw, status, "", ""])
continue
for name in consent:
button = page.get_by_role("button", name=name)
if button.count():
button.first.click()
page.wait_for_load_state("domcontentloaded")
break
if "/sorry/" in page.url:
print("%-40s captcha: change the session id in the login" % kw[:40], file=sys.stderr)
rows.append([kw, "captcha", "", ""])
continue
page.wait_for_timeout(WAIT_MS)
hosts = page.evaluate(FIND_BLOCK, labels)
except Exception as exc:
print("%-40s error: %s" % (kw[:40], str(exc).splitlines()[0]), file=sys.stderr)
rows.append([kw, "error", "", ""])
continue
if hosts is None:
print("%-40s no AI block" % kw[:40])
rows.append([kw, "no", "", ""])
continue
cited = sorted({bare(h) for h in hosts if "google." not in h})
mine = any(h == DOMAIN or h.endswith("." + DOMAIN) for h in cited)
print("%-40s AI block, %d sources, %s %s" % (kw[:40], len(cited), DOMAIN, "cited" if mine else "not cited"))
rows.append([kw, "yes", " ".join(cited), "yes" if mine else "no"])
browser.close()
with open(OUT_FILE, "w", encoding="utf-8", newline="") as f:
out = csv.writer(f, delimiter=";")
out.writerow(["keyword", "ai_block", "cited", "your_domain"])
out.writerows(rows)
print("saved", OUT_FILE)
if __name__ == "__main__":
main()
在 A-Parser 和 Key Collector 中,把 ip:port 列表粘贴到代理栏,并设置检查间隔,让同一关键词每天最多经过同一地址一次。Rank Tracker 等桌面工具读取代理文件,让它们指向生成脚本按国家写出的列表。
排名取决于查询从哪里发出,所以每个市场单独一份列表:每个国家一个追踪实例,只给它该国的地址。
上面的脚本通过对应国家的代理查询搜索引擎,并记录你的域名排在第几。请把搜索引擎的语言和地区参数与代理一起发送:地址决定国家,参数决定城市。
每次运行前用代理检测检查代理池;简单手动测试用免费代理列表就行。关于地区搜索结果的入门介绍会放在文章里。
Google越来越频繁地在常规结果上方放一个AI区块:一段简短的回答,附带来源链接。一部分点击会流向那里,所以您需要知道自己的网站是否进入了来源,以及哪些查询根本不显示该区块。区块按用户位置生成:同一个查询,柏林和慕尼黑可能看到不同的来源。
普通的搜索结果采集器永远看不到这个区块:Google在页面加载后用JavaScript渲染它。您需要真实浏览器,例如通过Playwright运行的Chromium,以及正确国家的家庭IP。列表地址在这类结果页上经常遇到验证码,所以这里由Resi Core和Resi Prime来完成。
国家级追踪用国家代码写在用户名里的Resi Core就够了。如果客户关心某个城市,请选Resi Prime,把城市写进字符串,并为每批查询固定会话:整批查询都会从该城市的同一个地址发出。
每天或每周跑一次关键词列表:AI区块的变化比常规排名慢。为每个查询记录日期、国家或城市、区块是否出现、它引用了哪些域名,以及您的域名是否在其中。一个月后就能看出AI把哪些页面纳入答案,哪些被移除了。
上面的第二个脚本正是把这些字段写入CSV。第一个脚本在同一国家追踪常规排名,所以两份报告可以按查询对齐。

国家级结果用Resi Core追踪,城市级结果用Resi Prime,大型关键词列表每天用不限流量套餐跑,更便宜。
国家级结果最佳选择
每次请求都用正确国家的家庭IP。搜索结果页很轻,1GB能覆盖上千次查询。
低至 $0.49 每GB1GB仅需$0.85
城市级结果
在连接字符串中设置城市和地区,就能得到该城市用户看到的结果。
低至 $1.39 每GB1GB仅需$2.29
大型关键词列表
每天数万次查询,不计流量。按CSV导出中的列选择市场国家。
$378 每月或每小时$2.10