转发一个PHP抓取网页快照程序,代码是转发的,注释是原创的,帮助新人理解。
snap.class.php
<?PHP
//====================================================
// FileName: snap.class.php
// Summary: 网页快照
// Author: millken(迷路林肯)
// LastModifed:2007-06-29
// copyright (c)2007 [email]millken@gmail.com[/email]
//====================================================
class snap{
var $dir;
var $log;
var $contents; // 缓冲文件内容
var $filename; // 缓冲文件的文件地址
var $host; // 目标地址
var $name; // 缓冲文件的文件名, 值是Url的MD5码
var $data_ts; // 缓冲文件的时间戳
var $ttl; // 超时时间
var $url; // 需要抓快照的Url地址
var $ts; //
function snap(){
$this->log = "New snap() object instantiated.<br />\n";
$this->dir = dirname(__FILE__)."/";
}
/*
获取网页快照。
参数:
url:网页地址
ttl:超时时间,单位为秒。
超过这个时间后从网页上获取,在此时间内直接读缓冲文件。
返回值:
无
*/
function fetch($url="",$ttl=10) {
$this->log .= "--------------------------------<br />fetch() called<br />\n";
$this->log .= "url: ".$url."<br />\n";
// 验证Url是否合法。
$hosts = parse_url($url);
$this->host = $hosts['scheme'].'://'.$hosts['host'].'/';
if (!$url) {
$this->log .= "OOPS: You need to pass a URL!<br />";
return false;
}
$this->ttl = $ttl;
$this->url = $url;
$this->name = md5($this->url);
$this->filename = $this->dir.$this->name;
$this->log .= "Filename: ".$this->filename."<br />";
$this->getFile_ts();
$this->file_get_content();
}
/*
获取快照内容。
如果超时,则从网页上直接获取,否则从缓存文件获取
参数:
无
返回值:
true:成功, false:失败
*/
function file_get_content(){
// 打开缓冲区
ob_start();
$this->ts = time() - $this->data_ts;
// 如果超时,则从网页上取得快照,否则,直接从缓冲区内取得
if($this->data_ts <> 0 && $this->ts <= $this->ttl){
$this->log .= "cache has expired<br />";
@readfile($this->filename);
$this->contents = ob_get_contents();
ob_end_clean();
}else{
$this->log .= "cache hasn't expired<br />";
@readfile($this->url);
$this->contents = ob_get_contents();
ob_end_clean();
$this->saveToCache();
}
return true;
}
/*
保存快照到缓存文件。
参数:
无
返回值:
true:成功, false:失败
*/
function saveToCache(){
$this->log .= "saveToCache() called<br />";
//建立一个新文件用户缓存网页快照
if (!$fp=@fopen($this->filename,"w")) {
$this->log .= "Could not open ".$this->filename."<br />";
return false;
}
$this->contents = $this->formaturl($this->contents, $this->host);
$this->contents = preg_replace("'<script[^>]*?>.*?</script>'si","",$this->contents);
//写文件
if (!@fwrite($fp,$this->contents)) {
$this->log .= "Could not write to ".$this->filename."<br />";
fclose($fp);
return false;
}
//关闭文件
fclose($fp);
return true;
}
/*
获得文件的时间戳
参数:
无
返回值:
true:成功, false:失败
*/
function getFile_ts() {
$this->log .= "getFile_ts() called<br />";
if (!file_exists($this->filename)) {
$this->data_ts = 0;
$this->log .= $this->filename." does not exist<br />";
return false;
}
$this->data_ts = filemtime($this->filename);
return true;
}
/*
格式化特殊的Url
参数:
无
返回值:
格式化后的Url。
*/
function formaturl($l1, $l2){
// 查询网页上的所有img,link,a
if (preg_match_all("/(<img[^>]+src=\"([^\"]+)\"[^>]*>)|(<link[^>]+href=\"([^\"]+)\"[^>]*>)|(<a[^>]+href=\"([^\"]+)\"[^>]*>)|(<img[^>]+src='([^']+)'[^>]*>)|(<a[^>]+href='([^']+)'[^>]*>)/i",$l1,$regs)){
foreach($regs[0] as $num => $url) {
$l1 = str_replace($url, $this->lIIIIl($url, $l2), $l1);
}
}
return $l1;
}
/*
将画面上的二级地址重新解析,以保证画面显示正确
例如:相对地址/css/sty004.css 会替换为绝对地址 http://xxx.com/css/sty004.css
参数:
$l1:要解析的地址
$l2:需要加上的host前缀
返回值:
格式化后的Url。
*/
function lIIIIl($l1, $l2) {
if(preg_match("/(.*)(href|src)\=(.+?)( |\/\>|\>).*/i", $l1, $regs)){
$I2 = $regs[3];
}
if(strlen($I2)>0) {
// 去掉双引号chr(34)和单引号chr(39)
$I1 = str_replace(chr(34),"",$I2);
$I1 = str_replace(chr(39),"",$I1);
} else {
return $l1;
}
$url_parsed = parse_url($l2);
$scheme = $url_parsed["scheme"];
if($scheme!="") {
$scheme = $scheme."://";
}
$host = $url_parsed["host"];
$l3 = $scheme.$host;
if(strlen($l3)==0)
{
return $l1;
}
$path = dirname($url_parsed["path"]);
if($path[0]=="\\") {
$path="";
}
$pos = strpos($I1,"#");
if($pos>0) {
$I1 = substr($I1,0,$pos);
}
//判断类型
if(preg_match("/^(http|https|ftp):(\/\/|\\\\)(([\w\/\\\+\-~`@:%])+\.)+([\w\/\\\.\=\?\+\-~`@\':!%#]|(&)|&)+/i",$I1)) {
return $l1;
//http类型的url要跳转;
} elseif($I1[0]=="/") {
//绝对路径
$I1 = $l3.$I1;
} elseif(substr($I1,0,3)=="../") {
//相对路径
while(substr($I1,0,3)=="../") {
$I1 = substr($I1,strlen($I1)-(strlen($I1)-3),strlen($I1)-3);
if(strlen($path)>0){
$path = dirname($path);
}
}
$I1 = $l3.$path."/".$I1;
} elseif(substr($I1,0,2)=="./") {
$I1 = $l3.$path.substr($I1,strlen($I1)-(strlen($I1)-1),strlen($I1)-1);
} elseif(strtolower(substr($I1,0,7))=="mailto:"||strtolower(substr($I1,0,11))=="javascript:") {
return $l1;
} else {
$I1 = $l3.$path."/".$I1;
}
return str_replace($I2,"\"$I1\"",$l1);
}
}
?>
test.php
<?php
require_once(dirname(__FILE__).'/snap.class.php');
$h = new snap();
$h->fetch($_GET['url']);
//echo $h->log;
echo $h->contents;
?>