对于JS最终生产get请求的情况:


有时候某些网站的列表页的分页条是通过Javascript创建的,例如:

http://www.gdcct.net/politics/headline/index.html

查看源代码可以看到是通过一个函数创建的:

<script language="javascript" type="text/javascript">    
createPageHTML(50, 0, "index", "html");    
</script>


这个JS函数会创建上一页下一页按钮,点击下一页,我们发现地址栏变成了:

http://www.gdcct.net/politics/headline/index_1.html

源代码中的JS函数变成了

createPageHTML(50, 1, "index", "html");

再点击下一页,则地址栏变成了

http://www.gdcct.net/politics/headline/index_2.html

源代码中的JS函数变成了

createPageHTML(50, 2, "index", "html");

这种情况下因为下一页链接是通过JS动态生成的,并没有出现在源代码中,因此常规的URL提取方式不能凑效。我们需要使用URL模板的方式来手动生成分页URL,需要参照下图所示配置URL层级:


采集URL模板支持使用模板来匹配HTML中的字符串,并根据匹配结果拼成新的URL,以便于加入到采集队列。 模板写法类似于:

{Regex:"window.location.href='./?Paging=${D:PageNo}'",Target:"?Pageing=${PageNo}",Form="site=1&page=${PageNo}"}

整个模板必须能够解析成合法的JSON对象,该JSON对象有三个成员变量,分别是:

1、 Regex,一个简易正则表达式,和模板匹配块一样,本类会使用此简易正则表达式从HTML中执行匹配,每匹配一次则形成一个变量的Map。 

2、 Target,目标URL表达式,是zhtml片段,可以使用zhtml中的表达式和函数。表达式求值时会从简易正则匹配形成的Map中查找变量。需要注意的是,有时候从模板中提取到变量值都是字符串,因此在生成的目标URL需要将页数加一时,需要使用类似${1+PageNo}的写法,如果使用$(PageNo+1)会变成字符串相加,从而得不到正确的目标URL。

3、 Form,表单变量表达式,也是一个zhtml片段,某些URL要求使用post提交表单后才能够正确地获回结果,此处即用于拼接表单变量字符串。


对于JS执行结果是提交post表单的情况:


有时候JS执行后是提交了form表单,以ASP.net中的分页最为常见。这种情况我们可以使用模板串中的Form属性来模拟表单提交,一般的步骤是:

1、 打开Chrome浏览器的Javascript控制台的“Network”选项卡。


2、 点击“下一页”或者别的分页按钮或者链接,这时查看post目标页面的Headers:

3、 分析哪些表单元素影响了分页,一般_VIEWSTATE是ASP.net中的ViewState技术自动添加,不需要考虑。在上面的例子中,真正起作用的表单元素是:


4、 因此我们通过往Form段中添加变量来模拟表单提交:

{Regex:"<option value=\"${D:PageNo}\">",Target:"FullTextSearchComProvisionsList.aspx",Form:"ID_ucFullTextSearchComProvisionsList$UcPager1$listPage=${PageNo}"}

注意:对于ASP.net表单,__VIEWSTATE,__EVENTTARGET已经自动加入到了模拟表单,不需要在这里列出。


5、 将Web采集任务设置成类似如下的起始URL,即可开始采集:

http://qt.ccsn.gov.cn/WebSite/FullTextSearch/FullTextSearchComProvisionsList.aspx

{Regex:"<option value=\"${D:PageNo}\">",Target:"FullTextSearchComProvisionsList.aspx",Form:"ID_ucFullTextSearchComProvisionsList$UcPager1$listPage=${PageNo}"}