结论:追踪蜘蛛首次访问的入口页面,不要看 Referer,而是从访问日志里按 User-Agent 筛出蜘蛛,再用「IP+User-Agent」切分会话,按时间排序后取每个会话第一条记录;要找全站首次,就取该蜘蛛所有日志中时间最早的一条。最后用反向 DNS 或官方 IP 段验证,避免 UA 伪装。
为什么蜘蛛的入口页面不能靠 Referer 判断?
结论:蜘蛛请求不带 Referer,日志里的 $http_referer 字段对蜘蛛为 "-",所以入口页面只能按时间序列确定。
搜索引擎蜘蛛是主动发起抓取,HTTP 请求头没有来源页面。普通用户从百度结果页点击进入,Referer 是 https://www.baidu.com/...;蜘蛛抓取 /article/123 时,Referer 为空或站内上一页。Nginx combined 日志中 Referer 是倒数第二个引号字段,蜘蛛行显示为 "-"。拿 Referer 找入口,会把蜘蛛误判为直接访问。
日志要满足什么格式和保留周期?
结论:Nginx 使用 combined 格式即可满足追踪需求,日志必须包含 User-Agent 和 Referer,且保留周期要覆盖首次访问日期。
Nginx 默认 combined 格式为:
$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"
文件在 /var/log/nginx/access.log,轮转后是 access.log.1、access.log.2.gz。如果 logrotate 只保留 7 天,而蜘蛛首次访问在 8 天前,日志已经删除,无法追踪。把 /etc/logrotate.d/nginx 里的 rotate 7 改成 rotate 30,可保留 30 份轮转日志。Apache 对应 /var/log/apache2/access.log* 或 /var/log/httpd/access_log*,格式同样用 combined。
怎么用脚本找出每个蜘蛛会话的第一条记录?
结论:按「IP+User-Agent」分组,组内按时间排序,相邻请求间隔超过 1800 秒就切一个新会话,每个新会话的第一条就是入口页面。
1800 秒是常用的会话超时阈值,蜘蛛连续抓取时相邻请求间隔小于 1800 秒;超过则视为新一次访问。执行下面 Python 脚本,它会自动读取 .gz 轮转日志,输出 IP、UA、时间、URL:
import re, gzip, glob, datetime
r = re.compile(r'^(\S+).*\[([^\]]+)\] "\S+ (\S+)[^"]*" \d+ \S+ "[^"]*" "([^"]*)"')
b = re.compile(r'Googlebot|bingbot|Baiduspider|YandexBot', re.I)
s = {}
for f in glob.glob('/var/log/nginx/access.log*'):
o = gzip.open if f.endswith('.gz') else open
for line in o(f, 'rt', errors='ignore'):
m = r.match(line)
if not m or not b.search(m.group(4)): continue
t = datetime.datetime.strptime(m.group(2), '%d/%b/%Y:%H:%M:%S %z')
s.setdefault((m.group(1), m.group(4)), []).append((t, m.group(3)))
for k, v in s.items():
v.sort()
last = None
for t, p in v:
if last is None or (t - last).total_seconds() > 1800:
print(k[0], k[1][:40], t.isoformat(), p)
last = t
如果只找全站首次,不看每个会话,把输出条件改为只保留该蜘蛛全局最早一行。若入口页面只统计内容页,在脚本里加 if re.search(r'/(robots\.txt|sitemap.*\.xml|favicon\.ico)$', p): continue,因为蜘蛛第一次抓取经常是 /robots.txt 或 /sitemap.xml。
怎么验证 IP 真是搜索引擎蜘蛛?
结论:User-Agent 可以被伪造,必须做反向 DNS 正查+反查一致,或对照官方 IP 段,否则会把假蜘蛛算进入口页面。
以 Googlebot 为例:
ip=66.249.66.1
dig +short -x $ip
dig +short crawl-66-249-66-1.googlebot.com
反查得到 crawl-66-249-66-1.googlebot.com,再正查该域名得到 66.249.66.1,两个结果一致才算真 Googlebot。Googlebot 官方 IP 段 JSON 是 https://developers.google.com/search/apis/ipranges/googlebot.json,Bingbot 是 https://www.bing.com/toolbox/bingbot.json。Bingbot 反查域名以 search.msn.com 结尾;百度蜘蛛可在百度搜索资源平台用抓取诊断和 IP 验证。
常见坑有哪些?
结论:分布式蜘蛛、日志轮转、时区排序和 robots 过滤是四个最容易出错的点。
- 分布式蜘蛛同一 UA 会用多个 IP。只按 UA 分组会把不同 IP 的抓取混在一起,入口页面错误;必须按 IP+UA 分组。
- 轮转日志必须一起读,
access.log* 要包含 .gz,脚本里用 gzip.open 就是为此。
- 时间不能按字符串排序。
10/Oct/2023 和 09/Nov/2023 按字符串排会乱,必须解析成带 %z 的 datetime 再排序。
/robots.txt、/sitemap.xml、/favicon.ico 常是蜘蛛第一次请求。要研究内容入口,先排除这些 URL。
按顺序做:确认日志保留 30 天以上,用 UA 筛出蜘蛛,用 IP+UA 以 1800 秒切会话,取每会话第一条,反向 DNS 验真,最后排除 robots/sitemap。这样得到的才是可验证的蜘蛛首次入口页面。