先给结论:蜘蛛请求的是编码后的 ASCII 地址
你在入口页里写 href="/tag/北京",浏览器地址栏可能显示成中文,但真正发到服务器的请求行,路径部分已经变成了 %E5%8C%97%E4%BA%AC 这类 UTF-8 百分号编码。搜索蜘蛛同样遵循这套规则:先把含有非 ASCII 字符的 IRI 按页面声明的字符编码转成 URI,再发起请求。所以日志里出现一串 %E5 开头的路径,并不代表被劫持或抓错,而是正常的编码结果。
有两点需要留意。一是编码结果取决于页面字符集,UTF-8 页面编出来的字节串和 GBK 页面完全不同;二是编码只是传输层的表示,链接指向的仍是同一份内容,如果服务器对两种写法都返回 200,就等于凭空多出一个 URL。
日志里怎么核对
- 看原始请求行的路径部分,而不是统计工具里已经解码过的报表。不少日志分析工具会默认把 %XX 还原成中文,看起来像“中文地址被访问了”,实际请求仍是编码形式。
- 如果服务器对未编码的中文路径直接返回 400 或 404,说明它没有做二次解码,蜘蛛抓到编码地址一般不受影响;但入口页里同时存在两种写法时,就会各抓一次。
- 把入口页源码里的 href 与日志路径逐条对照:能对上说明跟进正常;对不上,先查是否有重定向把地址改写成了另一种形式。
哪些字符最容易出问题
- 空格。href 里写 /a b.html,浏览器会补成 %20,但有些工具生成的链接会写成加号或干脆留空,蜘蛛请求时可能直接拿到 404。
- 方括号、花括号、竖线、反引号、尖括号。这些字符不允许直接出现在 URL 路径中,必须编码,否则部分服务器会直接拒绝。
- 查询串里的 & 与中文参数值。参数名和值里的中文同样要编码,& 如果没被正确转义,后面的参数会被截断。
- 井号 #。它属于片段标识,根本不会发送给服务器,这一点和前几类不同,不能指望靠编码把它变成路径的一部分。
容易造成重复 URL 的两种写法
- 大小写混用。同一路径,一处写 %E5%8C%97,另一处写小写 %e5%8c%97。多数服务器视为同一地址,抓取统计里却会算成两条,判断时以服务器实际返回的规范地址为准。
- 路径与查询串各写一种。/tag/北京 与 /tag/%E5%8C%97%E4%BA%AC 都返回 200,这时建议只保留一种形式,另一种做 301 到规范地址。
操作上的建议
- 入口页源码尽量直接写编码后的地址,至少保证全站写法统一,不要一部分页面写中文、一部分写编码。
- sitemap 也用编码后的形式,与页面 href 保持一致。两边写法不同,等于额外送了一批地址进去。
- 页面里加 canonical,指向你希望保留的那一种写法。
- 新链接上线前先用抓取工具本地跑一次,确认请求行的路径和预期一致,再放进蜘蛛池入口页。
一句话:蜘蛛不认“看起来好看”的中文地址,只认编码后能直接发出去的那串字符。入口页、sitemap、canonical 三处写法统一,比事后去猜日志里那串百分号是什么要省事得多。