-------------
前言
------------
最近在搞自动登录系统的框架。拿开心网001来实验,可是非常郁闷,我发现开心网的html页面是我所见到的所有页面中最不规范的。
水平之烂,第一次见。在php中夹杂Javascript,javascript有使用了php动态生成变量;在div布局中又嵌入table;json格式乱七八糟,根本没有统一的模型规范。
html标签不应该关闭的关闭,应该关闭的开着,几乎就是混乱。
我实在怀疑kaixin001到底能走多远。在几乎摇摇欲坠的架构上面开发,到底还有多少潜力?
虽然整个kaixin001如此之烂,而更令我惊奇是,无论IE、firefox、chrome依然能够正确的解析页面布局。实在佩服这些html解析器的内核,竟然可以容忍这么垃圾的html布局。
-------------
正文
------------
使用网络蜘蛛,首先必然要对html进行对象化,变成html树,然后再根据 class / id,甚至节点的位置获取自己需要的信息。
可以开心网的html如此之烂,采用标准的html规范解析,一定会崩溃的;既然ie的内核能够正确解析这种html,那么我一定可以进行类似的智能修正操作。
首先看一段kaixin001恶心的html代码,找找其中的问题。
代码
<
div
class
="dxx_of"
id
="message7"
onmouseover
="msgOnmouseover(7)"
onmouseout
="msgOnmouseout(7)"
/> ----------
问题1:毫无道理的中断
<
div
class
="dxx1"
style
="padding: 15px 10px;"
>
</
div
>
<
div
class
="dxx4"
>
<
div
class
="l50_s"
id
="icon7"
>
<
a
href
="/home/?uid=14682889"
title
="陈晨"
>
<
img
src
="http://pic1.kaixin001.com.cn/logo/68/28/50_14682889_24.jpg"
width
="50"
height
="50"
/></
a
></
div
>
<
div
style
="text-align: center; margin-top: -8px;"
>
<
a
href
="/home/?uid=14682889"
class
="sl"
title
="陈晨"
>
陈晨
</
a
></
div
>
</
div
>
<
div
class
="dxx5"
style
="width: 120px;"
>
<
div
class
="c9 f10"
>
3月24日
</
div
>
<
div
style
="display: none; border: 1px solid #EEC0C7; padding: 2px 5px 0 5px; color: #EEC0C7;"
>
群发
</
div
>
</
div
>
<
div
class
="dxx6"
>
<
table
width
="470"
class
="aa"
border
="0"
cellpadding
="0"
cellspacing
="0"
>
<
colgroup
>
<
col
width
="463"
/>
</
colgroup
>
<
tbody
>
<
tr
basestyle
="oRowLine2"
>
<
td
style
="white-space: normal"
valign
="top"
onclick
="javascript:clickDirect('/msg/view.php?thread_mid=1871989755&pos=6');"
>
<
img
onload
='_commentImageResize(this,350);'
title
="微笑"
src
="http://img1.kaixin001.com.cn/i/face/2.gif"
>
<
div
>
<
span
class
='c9'
>
共2条会话
</
span
><
a
href
="/msg/view.php?thread_mid=1871989755&pos=6"
class
="sl"
>
+展开
</
a
>
</
span
> -------- 问题2:没有根据的结束符 </
div
>
<
span
class
="c9"
></
span
>
<
div
class
="msg_encl"
style
="display: none;"
>
<
img
src
="http://img.kaixin001.com.cn/i/enclosure.gif"
/>
此消息含有0个附件
</
div
>
</
td
>
</
tr
>
</
tbody
>
</
table
>
</
div
>
<
div
class
="dxx4"
style
="width: 78px;"
>
<
div
>
<
a
class
="sl"
href
="/msg/view.php?thread_mid=1871989755&pos=6"
title
="查看该消息"
>
查看该消息
</
a
></
div
>
<
div
>
<
a
class
="sl"
href
="/msg/view.php?thread_mid=1871989755&pos=6"
title
="回复该消息"
>
回复该消息
</
a
></
div
>
<
div
>
<
a
class
="sl"
href
="/msg/write.php?thread_mid=1871989755"
title
="转发该消息"
>
转发该消息
</
a
></
div
>
<
div
id
="Div6"
style
="display: none;"
title
="举报不良短消息"
>
<
div
class
="l"
>
<
a
class
="sl cp"
style
="text-decoration: underline;"
onclick
="javascript:report(14682889,'1871989755');"
onmouseover
="javascript:$('reportimg').src='http://img.kaixin001.com.cn/i2/tanhao1.gif'"
onmouseout
="javascript:$('reportimg').src='http://img.kaixin001.com.cn/i2/tanhao.gif'"
target
="reportspam"
title
="举报不良短消息"
>
不良短消息
</
a
>
</
div
>
<
div
class
="l mt5"
>
<
img
id
="Img6"
onclick
="javascript:report(14682889,'1871989755');"
onmouseover
="this.src='http://img.kaixin001.com.cn/i2/tanhao1.gif'"
onmouseout
="this.src='http://img.kaixin001.com.cn/i2/tanhao.gif'"
src
="http://img.kaixin001.com.cn/i2/tanhao.gif"
width
="14"
height
="12"
alt
="举报不良短消息"
/></
div
>
<
div
class
="c"
>
</
div
>
</
div
>
</
div
>
<
div
class
="dxx7"
id
="delete7"
>
<
a
href
="javascript:delThread('1871989755', '0');"
title
="删除该条消息包含的所有会话"
>
<
img
src
="http://img.kaixin001.com.cn/i/close.gif"
/></
a
></
div
>
<
div
class
="c"
>
</
div
>
</
div
> --------
问题1:这个应该是开始的div的结束符
还有类似的代码,例如:
<
input
type
=hidden
name
=id_2
value
="9813861"
>
--------- 没有关上标签
<
input
type
=hidden
name
=num_2
value
="0"
>
<
input
type
=hidden
name
=del_2
value
="0"
>
总之,问题数不胜数。我大概列举一下:
1. 标签是否关闭问题
根据html规范,部分标签是不允许有子节点,例如br / hr / input / img 因此读取到当前节点之后,不会进行嵌套读取。
2. 布局的混乱
在第一个例子里面,
<div class="dxx_of" id="message7" onmouseover="msgOnmouseover(7)" onmouseout="msgOnmouseout(7)"/>
div过早的关闭了,如果按照html规范递推建立节点,则会导致子节点无法正确的建立。解决方法就是,当遇到当前节点是关闭的节点,例如<a xxx />,同时允许带有子节点,则进入递归继续读取。
3. 遇到结束节点
例如第一个例子里面多余的</span>,要解决这种问题,就需要对递归保存递归路径,使用堆栈Stack。当发生递归后,压入当前节点名称到堆栈,所以读取了结束节点,则判断是否在堆栈中出现过,如果没有,自动丢弃。
-------------
结束语
-------------
基本上以上3点,可以处理大部分的html代码了。只是还有一个问题,就是第二点的解决方案。
因为我是默认了可以包含子节点的html标签,忽略关闭记号继续迭代(忽略 />) ,则如果当前节点的确是需要关闭的,那么怎么办??
如果我知道ie的优化算法,估计这个问题可以被解决。
做网络爬虫的人应该占大多数,希望大家给点资料。