调皮的知乎戏耍了百度爬虫,背后发生了什么?

前两天刷微博时看到一条知乎的信息:

这是有人使用百度提供的索引搜索命令 site: zhuhu.com 来查询知乎在百度里的索引结果。大家能看出什么端倪吗?

说实话,其实不好察觉。

百度展示给用户的结果,通常有网页标题和网页的描述:网页标题来自于网页Html文档里的title,通常没有例外。但网页的描述可能来自于网页html文档里的description,也有可能是百度将整个网页筛选其中一段文本作为结果。

所以,这张展示知乎在百度里的索引结果可以看出有异样的是描述部分,可以看出来是清一色的“知乎宣传语”,博主也说了这叫“搜索引擎投毒”。

怎么理解这个说法,我想了一个形象的故事来比喻:知乎做着卖馒头的生意,每天络绎不绝的客户来吃,都是正常的馒头。而百度的工作是搜集各家店的食物用来做馒头Top100店铺的排名,于是他们派了大量的工作人员外出收集信息。当百度工作人员来到知乎的店里时,知乎看到老面孔一眼认出是百度的人,于是乎知乎把准备好的假馒头卖给了百度工作人员。而当百度的工作人员回到公司,才发现馒头掰开是一张纸条:知乎的馒头是最棒的。

这是我想了3分钟虚拟的小故事,希望能简单形象的道出了知乎做了什么事。

那真实的世界是怎么一回事呢?

百度包括各个搜索引擎都有个概念叫爬虫(Spider),虚拟的爬虫负责在网络世界里抓取海量的网页。而知乎就是通过识别百度的爬虫,并给予爬虫一种与普通用户不同的展示。所以网友的截图里就出现那样的现象。

那它背后是怎么实现的呢?说来也很简单。不管是爬虫还是真实用户,在发生网络请求的时候都会带上UserAgent这个属性。

User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

一些网站就常常通过判断 UA 来给不同的操作系统、不同的浏览器乃至不同的用户发送不同的页面。

知乎也是如此,我用一段示例代码来表示:

import userAgent from 'koa2-useragent';

router.get('/', async (ctx,next)=>{
    if(ctx.userAgent.isSpider){
    //当user agent来自于爬虫时
        await ctx.send(`
            <!DOCTYPE html>
            <html>
                <head>
                  <meta name="description" content="有问题,上知乎">
                  <title>喜欢上一个姑娘了怎么办?</title>
                </head>
                <body>
                  
                </body>
            </html>
        `)
    }
    else{
    //当user agent来自于真实用户时
        await ctx.send(`
            <!DOCTYPE html>
            <html>
                <head>
                  <meta name="description" content="泻药。说得像你上过似的">
                  <title>喜欢上一个姑娘了怎么办?</title>
                </head>
                <body>
                  
                </body>
            </html>
        `)
    }
})

这样,通过服务端判断请求的UserAgent可以实现针对不同身份的响应。至于知乎究竟出于什么目的不可得知,猜测也许是不想被百度这样的小偷窃取自己的真实海量信息。

在文章的尾声有必要说明的是,UserAgent是可以被伪造的。UserAgent的本质是Http请求头中的一个选项设置,通过编程的方式可以给请求设置任意的UserAgent。譬如这通常发生在,某些网站会限制非真实用户的访问(防止网页信息抓取),所以对UserAgent做了限制,而爬虫脚本就会在请求里面设置可以抓取的UserAgent以绕开限制。