最近发现有些搜索引擎爬虫在抓取数据的时候,先是通过一个HEAD 请求获取response的header 信息,然后再通过GET 请求获取response 的body信息(即页面的内容)——先发送HEAD 请求是为了获得页面的更新时间(即response header 中的Last-Modified 域),用于判断自从上一次该页面被收入索引库以后有没有被更新过,如果判断页面没有被更新过就忽略该页面,否则就再用GET 方法获取一次最新的内容并更新到索引库中。

在页面更新频率比较低或者缓存设置的时间比较长的情况下,这样做可以避免在网络上传送体积比较大的body 域、降低网络消耗,而且还也可以缩短索引的更新时间。但在页面更新频率比较高,或者页面缓存时间比较短的情况下效果却是相反的:

如果被抓取的页面在缓存中,情况会稍微好一些,缓存服务器(如安装了expires_module 的Apache)在接收到HEAD 请求时会把缓存后的response 的header 域返回给爬虫,在接下来的GET 请求时再把缓存后的整个response (包括header 域和body 域)都返回给爬虫;

如果被抓取的页面不在缓存中,而程序中又缺少专门针对HEAD 请求的处理方法,那么就会导致该页面被生成两次——在处理HEAD请求的时候,因为没有专门的方法,于是一般用于处理GET 请求的方法就会被执行,程序执行后生成了完整的response,缓存服务器接收到该response,但只会把它的header 信息返回给爬虫,并不会对该response 进行缓存;在处理接下来的GET 请求的时候,因为没有缓存所以程序还要再生成一遍完整的response,并由缓存服务器转交给爬虫,这时缓存服务器才会把response 缓存起来。这样程序就被执行了两次,第一次执行很大程序上来说是一种浪费。

解决问题的一种方法就是在程序中加入对HEAD 请求的处理。在处理HEAD 请求的时候一般只要设置response header 中Content-Type 和Content-Length 就可以了,如: 在servlet 可以通过重载doHead(HttpServletRequest request, HttpServletResponse response) 的方法实现:

public void doHead(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// Set the content length and type
resp.setContentType("text/html; charset=GB2312");
resp.setContentLength(30000);
}

而在jsp 中则可以仿照下面的方式:

<%
/* handle the HEAD request */
if(request.getMethod().equals("HEAD")) {
response.setDateHeader("Last-Modified", System.currentTimeMillis()); /* 设置Last-Modified */
response.setContentType("text/html; charset=GB2312"); /* 设置Content-Type */
response.setContentLength(30000); /* 设置 Content-Length */
return;
}
%>

下面是log 中的一个片断,显示了IP为202.108.1.4 的某个用户/爬虫/代理服务器(奇怪的UserAgent 项)的访问日志:
202.108.1.4 - - [06/Mar/2005:11:21:03 +0800] "HEAD /2001-03-07/28456.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:03 +0800] "GET /2001-03-07/28456.htm HTTP/1.1" 200 32182 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:09 +0800] "HEAD /2003-06-26/169417.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:09 +0800] "GET /2003-06-26/169417.htm HTTP/1.1" 200 34693 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:11 +0800] "HEAD /2005-1-5/361944.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:11 +0800] "GET /2005-1-5/361944.htm HTTP/1.1" 200 36761 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"

另,目前只有较少的老式搜索引擎爬虫在采用这种方式抓取页面,如AOL 的爬虫,而大部分搜索引擎爬虫都在采用另外一种方式:即在GET 请求的header 中加入If-Modified-Since 项,交由服务器判断页面是否被更新过。

参见:

    1. All About Search Indexing Robots and Spiders http://www.searchtools.com/robots/
    2. Stealth bots. How to detect them? http://www.webmasterworld.com/forum11/2562.htm
    3. 超文本传输协议 -- HTTP/1.0 (Hyptertext Transfer Protocol - HTTP/1.0)http://www.delphidevelopers.com/technical/RFC/RFCs/RFC1945.txt

加强对HEAD 请求的处理(转贴)的更多相关文章

  1. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  2. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  3. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

  4. Taurus.MVC 2.2 开源发布:WebAPI 功能增强(请求跨域及Json转换)

    背景: 1:有用户反馈了关于跨域请求的问题. 2:有用户反馈了参数获取的问题. 3:JsonHelper的增强. 在综合上面的条件下,有了2.2版本的更新,也因此写了此文. 开源地址: https:/ ...

  5. nodejs之get/post请求的几种方式

    最近一段时间在学习前端向服务器发送数据和请求数据,下面总结了一下向服务器发送请求用get和post的几种不同请求方式: 1.用form表单的方法:(1)get方法 前端代码: <form act ...

  6. ajax异步请求

    做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school.c ...

  7. C# MVC 5 - 生命周期(应用程序生命周期&请求生命周期)

    本文是根据网上的文章总结的. 1.介绍 本文讨论ASP.Net MVC框架MVC的请求生命周期. MVC有两个生命周期,一为应用程序生命周期,二为请求生命周期. 2.应用程序生命周期 应用程序生命周期 ...

  8. nodejs进阶(5)—接收请求参数

    1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...

  9. 无法向会话状态服务器发出会话状态请求。请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同。如果服务器位于远程计算机上,请检查。。。

    异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983.html 无法向会话状态服务器发出会话状态请求.请确保 ASP.NET State Ser ...

  10. [转]利用URLConnection来发送POST和GET请求

    URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和 URL 之间的通信链接.程序可以通过URLConnection实例向该URL发送请求.读取U ...

随机推荐

  1. 使用Amazon AWS SNS 发送 SMS 消息 .net

    1.浏览aws 开发人员指南 https://docs.aws.amazon.com/zh_cn/sns/latest/dg/sms_publish-to-phone.html 2.安装 aws sm ...

  2. 动态加载JS函数

    一般性的,当我们需要加载js文件的时候都会使用script标签来实现,类似于如下代码: 代码如下: <script type="text/javascript" src=&q ...

  3. 了解java虚拟机---JVM的基本结构(1)

    1. JVM的基本结构 1.1. 类加载子系统 类加载子系统负责从文件或者网络中加载Class信息,加载的类信息存放于方法区的内存空间.方法区中可能还会存放运行时常量信息,包括字符串与数字常量.(这部 ...

  4. Netty中消除开始的日志消息修改日志级别

    我是使用logback作为日志打印,之前使用slf4j,日志打印不出,就干脆换掉了. 1.首先引入依赖 <dependency> <groupId>ch.qos.logback ...

  5. 解决访问 jar 包里面的字体报错:OTS parsing error: incorrect file size in WOFF header

    前言:jar 包里面的字体加载,浏览器 console 中报警告信息,这里记录一下解决方案. 附:自己的一个 jar 包源码 https://github.com/yuleGH/querydb 错误问 ...

  6. HDU3625(SummerTrainingDay05-N 第一类斯特林数)

    Examining the Rooms Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  7. C# 8.0 范围类型 Range Type

    目录 C# 8 范围类型 Range Type: 范围缩写: 从一个索引开始到数组的最后一个对象 从数组的第一个对象到指定索引 整个数组: 从数组的某个索引开始一直到距数组尾部某个索引: 范围类型 替 ...

  8. cf900D. Unusual Sequences(容斥 莫比乌斯反演)

    题意 题目链接 Sol 首先若y % x不为0则答案为0 否则,问题可以转化为,有多少个数列满足和为y/x,且整个序列的gcd=1 考虑容斥,设\(g[i]\)表示满足和为\(i\)的序列的方案数,显 ...

  9. DouPHP去除Powered by DouPHP版权的方法

    DouPHP标题版权修改:打开 include 目录下的 action.class.php 文件,搜索“Powered”找到下面一行代码: $page_title = ($titles ? $titl ...

  10. ethernaut 以太坊靶场学习 (1-12)

    前言 这个靶场搜集了许多不同的 solidity 开发的问题,通过这个可以入门 区块链安全 Fallback 给出了源码 pragma solidity ^0.4.18; import 'zeppel ...