加强对HEAD 请求的处理(转贴)
最近发现有些搜索引擎爬虫在抓取数据的时候,先是通过一个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 项,交由服务器判断页面是否被更新过。
参见:
- All About Search Indexing Robots and Spiders http://www.searchtools.com/robots/
- Stealth bots. How to detect them? http://www.webmasterworld.com/forum11/2562.htm
- 超文本传输协议 -- HTTP/1.0 (Hyptertext Transfer Protocol - HTTP/1.0)http://www.delphidevelopers.com/technical/RFC/RFCs/RFC1945.txt
加强对HEAD 请求的处理(转贴)的更多相关文章
- Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求
上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...
- Android请求网络共通类——Hi_博客 Android App 开发笔记
今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...
- 重温Http协议--请求报文和响应报文
http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...
- Taurus.MVC 2.2 开源发布:WebAPI 功能增强(请求跨域及Json转换)
背景: 1:有用户反馈了关于跨域请求的问题. 2:有用户反馈了参数获取的问题. 3:JsonHelper的增强. 在综合上面的条件下,有了2.2版本的更新,也因此写了此文. 开源地址: https:/ ...
- nodejs之get/post请求的几种方式
最近一段时间在学习前端向服务器发送数据和请求数据,下面总结了一下向服务器发送请求用get和post的几种不同请求方式: 1.用form表单的方法:(1)get方法 前端代码: <form act ...
- ajax异步请求
做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school.c ...
- C# MVC 5 - 生命周期(应用程序生命周期&请求生命周期)
本文是根据网上的文章总结的. 1.介绍 本文讨论ASP.Net MVC框架MVC的请求生命周期. MVC有两个生命周期,一为应用程序生命周期,二为请求生命周期. 2.应用程序生命周期 应用程序生命周期 ...
- nodejs进阶(5)—接收请求参数
1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...
- 无法向会话状态服务器发出会话状态请求。请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同。如果服务器位于远程计算机上,请检查。。。
异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983.html 无法向会话状态服务器发出会话状态请求.请确保 ASP.NET State Ser ...
- [转]利用URLConnection来发送POST和GET请求
URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和 URL 之间的通信链接.程序可以通过URLConnection实例向该URL发送请求.读取U ...
随机推荐
- android 日期控件 DatePicker
DatePicker的缺陷 提供的API太少,没办法个性化定制.比如,不能指定某部分的颜色,不能控制显示的部分等. xml中提供的属性太少,同样影响定制化. 兼容性问题太多,在4.x,5.x和6.0+ ...
- maven的注意点
一.dependency的scope 取值范围:compile.test.runtime.provided.system compile 默认就是compile,什么都不配置也就是意味着compile ...
- 盒子模型的margin负数用法
盒子的margin用法大家都应该很清楚,在实际中一般使用margin来水平居中或者让自己移动相应的位置,但是margin给负数在实际中也是有用的. 如图为两个浮动的盒子. 给左边的盒子margin-l ...
- 查看centos操作系统、java_jdk、hadoop位数
1.centos操作系统位数: file /bin/ls 此为64位 2.java jdk 位数: java -version 这个是64为的,若是没有,则默认为32位 3.hadoop位数: 进入h ...
- python移位运算符
1,二进制方式 >>> bin( 1 ) '0b1' >>> bin( 10 ) '0b1010' >>> a = 0b10 >>&g ...
- 自定义高级版python线程池
基于简单版创建类对象过多,现自定义高级版python线程池,代码如下 #高级线程池 import queue import threading import time StopEvent = obje ...
- 你不知道的JavasScript上篇·第三章·对象
1.Object.defineProperty()&&getter.setter Object.defineProperty(目标对象,属性名(string型),{ get:funct ...
- MRO + super面试题(详解)
class Init(object): def __init__(self, v): print("init") self.val = v class Add2(Init): de ...
- JS代理模式实现图片预加载
---恢复内容开始--- 刚刚说了懒加载,现在我们来搞搞预加载吧 预加载的核心: 图片等静态资源在使用前提前请求. 资源后续使用可以直接从缓存中加载,提升用户体验. 几个误区: 预加载不是为了减少页面 ...
- ActiveReports 报表应用教程 (12)---交互式报表之贯穿钻取
在葡萄城ActiveReports报表中提供强大的数据分析能力,您可以通过图表.表格.图片.列表.波形图等控件来实现数据的贯穿钻取,在一级报表中可以通过鼠标点击来钻取更为详细的数据. 本文展示的是20 ...