我的需求是这样的:
我是名研究微博的学生,目前在做腾讯微博中普通用户(定义为收听数和听众数都小于1000的用户)的关系网络研究,我想通过metaseeker来实现这个目的。
我目前是这么做的:
对于抓取关系网络,我通过将定义的Info线索指向工程自身来模拟实现宽度优先搜索,定义的工程名是‘QQ_microblog_following’。目前这个工程是按照教程的一般方法设置的,因此能够把线索指向的页面上的所有用户给抓取下来,并把他们的超链接做成新的线索。但这不能满足我的需求,因为这些用户中必然有不少不是普通用户,如果以这些非普通用户的超链接作为线索,会严重增加下一轮下载的负担,并且后期处理我不得不再写程序来过滤掉这些非普通用户。
因此我希望在进行内容映射这些线索链接的时候,能够过滤掉那些收听数或听众数大于1000的用户,但以目前metaseeker的功能,我发现很难做到这点,请问有何解决方法没有?
目前,’QQ_microblog_following‘的MAP文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Follow_List>
<xsl:apply-templates select="//*[@id='mainWrapper']/div[position()=1]/div[position()=5]/ul/li[position()>=1]" mode="Follow_List"/>
</Follow_List>
</xsl:template>
<xsl:template match="*//*[@class='userNums']" mode="F_Link">
<item>
<F_Listen_Num>
<xsl:value-of select="span[position()=1]/a/strong/text()"/>
</F_Listen_Num>
<F_Listen_Page>
<xsl:value-of select="span[position()=1]/a/@href"/>
</F_Listen_Page>
<F_Follow_Num>
<xsl:value-of select="span[position()=2]/a/strong/text()"/>
</F_Follow_Num>
<F_Follow_Page>
<xsl:value-of select="span[position()=2]/a/@href"/>
</F_Follow_Page>
</item>
</xsl:template>
<xsl:template match="*[@class='userNums']" mode="F_Link">
<item>
<F_Listen_Num>
<xsl:value-of select="span[position()=1]/a/strong/text()"/>
</F_Listen_Num>
<F_Listen_Page>
<xsl:value-of select="span[position()=1]/a/@href"/>
</F_Listen_Page>
<F_Follow_Num>
<xsl:value-of select="span[position()=2]/a/strong/text()"/>
</F_Follow_Num>
<F_Follow_Page>
<xsl:value-of select="span[position()=2]/a/@href"/>
</F_Follow_Page>
</item>
</xsl:template>
<xsl:template match="//*[@id='mainWrapper']/div[position()=1]/div[position()=5]/ul/li[position()>=1]" mode="Follow_List">
<item>
<F_Name>
<xsl:value-of select="*//*[@class='userName']/strong/a/text()"/>
<xsl:value-of select="*[@class='userName']/strong/a/text()"/>
<xsl:if test="@class='userName'">
<xsl:value-of select="strong/a/text()"/>
</xsl:if>
</F_Name>
<F_Main_Page>
<xsl:value-of select="*//*[@class='userName']/strong/a/@href"/>
<xsl:value-of select="*[@class='userName']/strong/a/@href"/>
<xsl:if test="@class='userName'">
<xsl:value-of select="strong/a/@href"/>
</xsl:if>
</F_Main_Page>
<F_Link>
<xsl:apply-templates select="*//*[@class='userNums']" mode="F_Link"/>
<xsl:apply-templates select="*[@class='userNums']" mode="F_Link"/>
</F_Link>
</item>
</xsl:template>
</xsl:stylesheet>
这个配置文件中,F_Listen_Num,F_Follow_Num分别是页面上的人的听众数量和收听数量;F_Listen_Page,F_Follow_Page则分别定义是页面上的人的听众链接和收听链接。按照我的需求,只有当F_Listen_Num,F_Follow_Num引用的两个数值都小于1000时,才将F_Follow_Page作为线索超链接。 要实现这个功能,配置文件在F_Follow_Page这项的设置中,应该增加<xsl:if>来进行判断,方式如下:
<F_Follow_Page>
<xsl:if test="span[position()=1]/a/strong/text() < 1000 and span[position()=2]/a/strong/text() < 1000">
<xsl:value-of select="span[position()=2]/a/@href"/>
</xsl:if>
</F_Follow_Page>
这样,但听众数或收听数其中一个大于1000的时候,F_Follow_Page的值都为空,也就不能够成为线索了,就达到了过滤的目的了。
请问这种情况下,如何在内容映射时使用xpath加入<xsl:if>,实现内容的过滤呢?
可以使用自定义XSLT片段
自定义XPath功能无法实现你的需求,因为抓取规则是程序自动生成的,只能使用XPath允许的函数达到自定义XPath的目的,这个功能有限。
所以,需要使用自定义XSLT方法,可以观察一下F_Link信息属性,它使用apply-templates调用了一个XSL片段,这个片段是程序自动产生的,你也可以自己写,在设置信息属性的特性的时候,选择XSLT过滤器,然后输入一个XSL片段,继续参照F_Link自动生成的片段,你需要填入的自定义片段是不包括框子的那部分,即F_Link中item标签之内的部分。
自定义XSLT很难调试,你可能需要花点时间,遇到问题可以继续问。
通常,我们不用这种方法,我们一般在处理抓取结果上进行过滤或者生成线索,只有企业版用户才能操作数据库,或者对其编程。如果你有比较多的经费,可以考虑购买MetaSeeker企业版,不过价格挺贵的。
能否对XSLT的作用机制讲得更清晰些?
试了很久,发现在F_Link这个容器里无论怎么定义的XSLT片段并没有整合到输出的MAP文件里面,那这个XSLT片段是如何工作的呢?
我想理解的清楚更深刻的问题:
如果对于一个block属性的叶子节点,我想设置XPATH过滤或者XSLT过滤都好实现,在对应的区域插入输入的片段代码即可。
但如果对于一个block属性的容器节点,可能设置的XPATH或XSLT于它下面的节点的定义发生冲突,举个例子:
就如我这儿定义的容器节点F_Link,它下面有四个叶子节点如下:
F_Link:
F_Listen_Num:
F_Listen_Page:
F_Follow_Num:
F_Follow_Page:
这下面的四个节点一开始都已经明确了其抓取规律。当我们在对F_Link设置XPATH和XSLT过滤后,这四个叶子节点在具体映射的时候,是使用过滤后的HTML片段来映射,还是依然使用原文HTML片段来映射呢?
容器节点的XSLT过滤规则
通常不为容器节点定义XSLT过滤过则。既然是自定XSLT规则,那么规则内是否有叶子节点都是你自己说了算。所以,如果想为F_Link定义XSLT片断,则不需要用MetaStudio定义下面的叶子节点,只需在XSLT片断中出现这些叶子节点即可。
节点设置为Key属性后能够起到一定的过滤作用
一次偶然的机会发现,当把一个叶子节点元素设置成为Key属性后,这个节点外面的容器节点的规则定义就会增加,形式如下:
<FollowBckt>
<xsl:apply-templates select="//*[@class='listWrapper' and count(.//*[@class='LC']/li[position()>=1 and count(.//*[@class='userNums']/span[position()=1]/a/strong/text())>0])>0]" mode="FollowBckt"/>
</FollowBckt>
其中的count(.//*[@class='userNums']/span[position()=1]/a/strong/text())>0])>0这条规则就是增加的用于保证叶子节点存在的规则。
按照这个思路,可否考虑对这个Key的功能进一步扩展下,以实现个性化的过滤功能呢?
这是一个很好的扩展建议
因为规则主要靠程序自动生成,那么自定义的规则必须要与自动生成的规则很好的契合在一起,这一点一直没有找到很好的解决方案,所以,自定义能力受到了很大限制。