颠覆想象的php解析获取跨域HTML标签
本文利用php实现跨域解析获取HTML标签,返回值中将包含1个或多个匹配的标签结果。
从图中可看出,输入参数包括:URL链接,HTML源码,标签名,标签属性,是否仅匹配第一项。
1、URL链接
用于非输入HTML源码情况下获取HTML源码。这个较为通用。
2、HTML源码
任意用于测试用的HTML源码都可以。
3、标签名
标签名可为任意HTML标签,包括div,ul,table等。
4、标签属性
标签属性可用于精确匹配标签,可为:id="main",class="p",name="task",border="0px"等。
5、是否仅匹配第一项
只获取第一条返回结果。
一些效果图如下:
(图一 URL链接方式)
(图二 直接输入HTML源码方式)
(图三 匹配class属性)
(图四 匹配所有<a>标签)
(图五 只获取第一个匹配项)
源码展示:
index.html
1 <html> 2 <head> 3 <title>parse DIV</title> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <meta http-equiv="Content-Language" content="zh-CN" /> 6 <script type="text/javascript" src="https://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> 7 </head> 8 <body> 9 <span><div>请输入URL链接:</div><input type="text" id="url" value="http://www.baidu.com/">(如:http://www.baidu.com/)</span> 10 <span><div>此次可直接输入页面HTML:</div><input type="text" id="data" value="">(若输入请清空上面URL链接)</span> 11 <span><div>请输入HTML标签名:</div><input type="text" id="tag" value="div">(如div,ul,table,tr,img,input,h1等)</span> 12 <span><div>请输入HTML标签的属性:</div><input type="text" id="tag_id" value='id="u"'>(如id="main",id='main',class="p",name="task"等,可留空匹配无属性标签,区分单双引号)</span> 13 <span><div>只获取第一个匹配项:</div><input type="radio" id="first" now-v="unchecked"></span> 14 <span><input type="button" value="提交" id="parse"></span> 15 <span>解析结果:</span> 16 <textarea id="result" style="float:left;" cols="150" rows="20"></textarea> 17 <script type="text/javascript"> 18 $(document).ready(function(){ 19 //初始化 20 $("body").css({"background-color":"#ABC"}); 21 $("span").css({"float":"left","clear":"both","padding":"3px"}); 22 $("div").css({"float":"left","width":"300px"}); 23 $("input").attr('size',40); 24 $("#first").attr('checked',null); 25 //单选按钮操作 26 $("#first").unbind().click(function(){ 27 if($(this).attr('now-v') == 'unchecked') $(this).attr('checked','checked').attr('now-v','checked'); 28 else $(this).attr('checked',null).attr('now-v','unchecked'); 29 }) 30 //提交处理 31 $("#parse").click(function(){ 32 var tag_id,url,tag,data,parentBegin='',parentEnd=''; 33 var first = encodeURIComponent($("#first").attr('now-v')); 34 $("input[type=text]").each(function(){ 35 var name = $(this).attr('id'); 36 var value = $.trim($(this).val()); 37 if(value == '') value='EmPtYValue'; 38 value = encodeURIComponent(value); 39 eval(name+'="'+value+'"'); 40 if(eval(name) == '') return false; 41 }); 42 switch(tag){ 43 case 'td': 44 parentBegin = '<table><tr>'; 45 parentEnd = '</tr></table>'; 46 break; 47 case 'tr': 48 parentBegin = '<table>'; 49 parentEnd = '</table>'; 50 break; 51 case 'li': 52 parentBegin = '<ul>'; 53 parentEnd = '</ul>'; 54 break; 55 case 'dt': 56 parentBegin = '<dl>'; 57 parentEnd = '</dl>'; 58 break; 59 default: 60 parentBegin = ''; 61 parentEnd = ''; 62 break; 63 } 64 65 $.ajax({ 66 url:'parseHtml.php', 67 type:'POST', 68 dataType:'json', 69 async:false, 70 data:{"tag_id":tag_id,"url":url,"tag":tag,"data":data,"first":first}, 71 success:function(msg){ 72 if(msg != '没有匹配项!') var count = "一共获得"+msg.length+"个匹配。\n"; 73 else var count = ''; 74 $("#result").html(count+parentBegin+msg.toString().replace(/>,</g,">\n<")+parentEnd); 75 // alert(msg[0]); //获取第1个匹配 76 // alert($(msg[1]).html()); //获取第2个匹配html内容 77 }, 78 error:function(){ 79 alert("服务器出错"); 80 } 81 }); 82 }); 83 }); 84 </script> 85 </body> 86 </html>
parseHtml.php
1 <?php 2 header("Content-type: text/html; charset=utf-8"); 3 function getWebTag($tag_id,$url=false,$tag='div',$data=false,$first=false){ 4 //默认采用URL获取数据 5 if($url !== false){ 6 $data = file_get_contents( $url ); 7 } 8 //页面编码判定及转码 9 $charset_pos = stripos($data,'charset'); 10 if($charset_pos) { 11 if(stripos($data,'charset=utf-8',$charset_pos)) { 12 $data = iconv('utf-8','utf-8',$data); 13 }else if(stripos($data,'charset=gb2312',$charset_pos)) { 14 $data = iconv('gb2312','utf-8',$data); 15 }else if(stripos($data,'charset=gbk',$charset_pos)) { 16 $data = iconv('gbk','utf-8',$data); 17 } 18 } 19 20 //匹配命中标签至数组$hits 21 preg_match_all('/<'.$tag.'[^<]*?'.$tag_id.'/i',$data,$hits,PREG_OFFSET_CAPTURE); 22 if(count($hits[0]) === 0) { //未命中,直接返回 23 return '没有匹配项!'; 24 } 25 26 preg_match_all('/<'.$tag.'/i',$data,$pre_matches,PREG_OFFSET_CAPTURE); //获取所有HTML标签前缀 27 preg_match_all('/<\/'.$tag.'/i',$data,$suf_matches,PREG_OFFSET_CAPTURE); //获取所有HTML标签后缀 28 29 //判断是否<div></div>格式,是则添加结束标签,否则为false; 注:img、input等可能不是这种格式,此时$suf_matches[0]为空。 30 if(!empty($suf_matches[0])) $endTag = '</'.$tag.'>'; 31 else $endTag = false; 32 33 //合并所有HTML标签 34 $htmltags = array(); 35 if($endTag !== false){ 36 foreach($pre_matches[0] as $index=>$pre_div){ 37 $htmltags[(int)$pre_matches[0][$index][1]] = 'p'; 38 $htmltags[(int)$suf_matches[0][$index][1]] = 's'; 39 } 40 }else{ 41 foreach($pre_matches[0] as $index=>$pre_div){ 42 //非<div></div>格式,获取前缀下标后的第一个>作为标签结束 43 $suf_matches[0][$index][1] = stripos($data,'>',$pre_matches[0][$index][1])+1; 44 45 $htmltags[(int)$pre_matches[0][$index][1]] = 'p'; 46 $htmltags[(int)$suf_matches[0][$index][1]] = 's'; 47 } 48 } 49 //对所有HTML标签按index进行排序 50 $sort = array_keys($htmltags); 51 asort($sort); 52 53 //开始获取命中字符串 54 $hitTagStrings = array(); 55 foreach($hits[0] as $hit){ 56 $hit = $hit[1]; //获取命中index 57 58 $count = count($sort); //循环控制,$count--避免无限循环 59 foreach($pre_matches[0] as $index=>$pre_div){ 60 //最后一个$pre_matches[0][$index+1]会造成数组出界,因此设置其index等于总长度 61 if(!isset($pre_matches[0][$index+1][1])) $pre_matches[0][$index+1][1] = strlen($data); 62 63 //<div $hit <div+1 时div被命中 64 if(($pre_matches[0][$index][1] <= $hit) && ($hit < $pre_matches[0][$index+1][1])){ 65 $deeper = 0; 66 //弹出被命中HTML标签前的所有HTML标签 67 while(array_shift($sort) != $pre_matches[0][$index][1] && ($count--)) continue; 68 //对剩余HTML标签进行匹配,若下一个为前缀(p),则向下一层,$deeper加1, 69 //否则后退一层,$deeper减1,$deeper为0则命中匹配结束标记,计算div长度 70 foreach($sort as $key){ 71 if($htmltags[$key] == 'p') { //进入子层 72 $deeper++; 73 }else if($deeper == 0) { //碰到结束标记 74 $length = $key-$pre_matches[0][$index][1]; //长度等于结束标记index 减去 前缀index 75 break; 76 }else { //碰到子层结束标记 77 $deeper--; 78 } 79 } 80 $hitTagStrings[] = substr($data,$pre_matches[0][$index][1],$length).$endTag; 81 break; 82 } 83 } 84 //若只获取第一个匹配项,退出循环 85 if($first && count($hitTagStrings) == 1) break; 86 } 87 88 return $hitTagStrings; 89 } 90 91 $tag_id = urldecode($_POST['tag_id']); 92 $url = urldecode($_POST['url']); 93 $tag = isset($_POST['tag'])? urldecode($_POST['tag']) : 'div'; 94 $data = urldecode($_POST['data']); 95 $first = (urldecode($_POST['first']) == 'checked')? true : false; 96 foreach($_POST as $key => $value){ 97 if($value == 'EmPtYValue') $$key = false; 98 } 99 echo json_encode(getWebTag($tag_id,$url,$tag,$data,$first)); 100 101 //End_php
注:phpQuery类似jQuery语法实现,非常简便。