0 1

网站的搜索关键词和访问地图

用网络日志分析软件AWStats对网站的log进行分析时发现几个问题:

  • 无法同时分析出utf-8和gb2312等多种编码的搜索关键词, 关键词表中总会出现一些乱码;
  • 不知道如何按照访问日期对关键词排序;
  • 不知道如何制作过滤搜索引擎的访问地图;

因为Perl语言看起来的确很烦,所以与其搜索AWStats的解决方案,不如自己用Python写一个程序来获取这些信息。

分析的结果可以参看: 搜索关键词表 访问地图

制作关键词表

关键词在log中的Referer中寻找如下格式:

KeyTable = {"google":("q","utf-8"), "baidu":("wd","gb2312"), 
"yahoo":("p","utf-8")}

"google":("q","utf-8")表示对于包含google的referer,寻找参数q=...,并按照utf-8编码进行解码。如果解码失败会依次尝试别的编码。这样就解决了关键词编码的问题。

制作访问地图

下图是使用GoogleMap制作访问地图的截屏。为了过滤搜索引擎的IP,先统计出log中所有的User-Agent,然后人工找到疑似搜索引擎的Agent。

下面是对本网站的统计结果,包含如下字符串的Uer-Agent的IP均不在统计之列:

SearchEng = ["Googlebot", "Baiduspider", "NaverBot", "Exabot", 
"woriobot", "Doubanbot", "Feedfetcher-Google",
"Yahoo! Slurp", "Twiceler", "msnbot", "e-SocietyRobot", "iearthworm",
"YodaoBot-Reader", "help.naver.com", "Jakarta"]

地图中的地点标示的大小按照页面的访问次数设置,只对如下的文件类型进行访问计数:

PageType = [".html", ".htm", ".py"] 

地点标示的直径与访问次数的平方根成正比,并且设置最小直径为4个像素。每个地点标示都记录了其最后访问日期、IP地址数、页面访问次数以及IP地址列表。

IP地址到地点坐标的转换是用下面的程序从http://whatismyipaddress.com自动抓取而得。它先在缓存文件IpLocation中查找,如果没有找到就用urllib2库抓取网页,并对结果进行正则表达式搜索。

01import urllib2
02import urllib
03import re
04import pickle
05 
06try:
07    ipdict = pickle.load(file("IpLocation","rb"))
08except:
09    ipdict = {}
10 
11def getIpLocation(IP):
12    if IP in ipdict:
13        return ipdict[IP]
14    url = "http://whatismyipaddress.com/staticpages/index.php/lookup-results"
15    req = urllib2.Request(url)
16    req.add_header("User-Agent",
17"Mozilla/5.0 (Windows NT 5.1; U; zh-cn) Opera 9.00")
18    data = {'LOOKUPADDRESS': IP, 'Lookup IP Address': 'Lookup IP Address'}
19    req.add_data(urllib.urlencode(data))
20    f = urllib2.urlopen(req)
21    data = f.read()
22    f.close()
23    result = re.compile("GLatLng\((.+?)\)").search(data)
24    if result:
25        location = tuple((x.strip() for x in result.group(1).split(",")))
26        ipdict[IP] = location
27        print location
28        return location
29    else:
30        return None
31 
32def saveIpLocation():
33        pickle.dump(ipdict, file("IpLocation", "wb"))


Python解S先生与P先生谜题

这道题目来自美国斯坦福大学的麦卡锡教授----S先生与P先生谜题。

题目:S先生与P先生谜题

设有两个自然数X、Y,2<=X<=Y<=99,S先生知道这两个数的和S,P先生知道这两个数的积P,他们二人进行了如下对话:

  • S:我确信你不知道这两个数是什么,但我也不知道。
  • P: 一听你说这句话,我就知道这两个数是什么了。
  • S: 我也是,现在我也知道了。

现在你能通过他们的会话推断出这两个数是什么吗?(当然,S和P先生都是非常聪明的)

关于这道题目的解题思路可以参考: Prolog教程S先生与P先生

01from math import sqrt
02 
03MIN, MAX = 2, 99
04#只需要判断y的范围, 程序确保x的取值范围
05def BaseCondition(x, y):
06    if y >= MIN and y <= MAX and y >= x: return True
07    return False
08 
09#S先生的S分析
10def S(x, y):
11    s = x + y
12    return [(x,s-x) for x in xrange(MIN, s/2+1)]
13 
14#P先生的P分析
15def P(x, y):
16    p = x * y
17    return [(x,p/x) for x in xrange(MIN, int(sqrt(p)+1))
18            if p%x==0 and BaseCondition(x, p/x)]
19 
20#所有待检查的数据
21def ToCheck():
22    return ((x,y) for x in xrange(MIN, MAX+1) for y in xrange(x, MAX+1))
23 
24#条件1 - S:我确信你不知道这两个数是什么,但我也不知道。
25def Condition1(x, y):
26    s_sep = S(x, y)
27    if len(s_sep) == 1: return False # S分析唯一
28    for x1, y1 in s_sep:
29        if len(P(x1, y1)) == 1: return False #P分析唯一
30    return True
31 
32#条件2 - P: 一听你说这句话,我就知道这两个数是什么了。
33def Condition2(x, y):
34    p_sep = [c for c in P(x,y) if c!=(x,y)] #除(x,y)之外的P分析
35    for item in p_sep:
36        if Condition1(*item): return False #若还有满足条件1的解则失败
37    return True
38 
39#条件3 - S: 我也是,现在我也知道了。
40def Condition3(x, y):
41    s_sep = [c for c in S(x, y) if c!=(x,y)] #除(x,y)之外的S分析
42    for item in s_sep:
43        if Condition2(*item): return False #若还有满足条件2的解则失败
44    return True
45 
46#需要同时满足上面3个条件
47def Condition(*c):
48    return Condition1(*c) and Condition2(*c) and Condition3(*c)
49 
50result = (c for c in ToCheck() if Condition(*c))
51print result.next()
 


海月挨打

我还没吃呢,哪有吃的给你。

和小猫对视

人家都说小孩子三岁之前是一个养成良好习惯的重要阶段,一想到这我有的时候就会对海月很严厉。今天中午海月似乎不是很饿,没有吃多少饭。于是我就把饭放在桌子上让她自己想吃就吃。结果她看我不管她,就故意把饭撒在地上。当时我一方面非常生气,一方面想告诉她这样做非常不好,就顺手打了她的屁股一下,还做出很生气的表情。这样一来她就大哭起来,喊着要睡觉要睡觉,我想给她水喝,也完全喂不进去了。有的时候真的搞不清楚到底怎么样做才是教育孩子的最佳方式。


C55x的Boot Table问题

RY 隐藏 2008/03/28

Run-time和load-time初始化 一文中,我曾经介绍过C55x系列的Boot Table的格式,以及设置为load-time格式时hex55工具对.cinit段的展开工作。可是在实际的开发中我发现hex55工具(v3.2.2)对.cinit的处理竟然是错误的。下面我就来详细分析一下这个错误。

上图是hex5x产生的boot table的格式。根据此图,编写如下Python程序显示Boot Table中的每个项目。注意图中的Section Byte Count可能为奇数,而其下面的Data Byte的个数必须为偶数,因此当Section Byte Count为奇数的时候,会多出一个填充字节。

01import os, sys, struct
02 
03def list_boottable(filename):
04    f = file(filename, "rb")
05    data = f.read(4)
06    # entry point
07    entry_point_address = struct.unpack("!L", data)[0]
08    print "entry point:", hex(entry_point_address)
09    # register
10    data = f.read(4)
11    register_configuration_count = struct.unpack("!L", data)[0]
12    print "register count:", register_configuration_count/2
13    for i in xrange(register_configuration_count/2):
14        data = [hex(struct.unpack("!H", f.read(2))[0]) for i in range(4)]
15        print data[0], "=", data[1]
16        print "delay", data[2] , ",", data[3]
17    # copy table
18    while 1:
19        data = f.read(4)
20        section_byte_count = struct.unpack("!L", data)[0]
21        if section_byte_count == 0: break
22        data = f.read(4)
23        section_start_address = struct.unpack("!L", data)[0]
24        print hex(section_start_address), "<-", hex(section_byte_count), "bytes"
25        data = f.read(section_byte_count)
26        # if byte count is odd, read a padding byte
27        if section_byte_count%2==1:
28            data = f.read(1)
29    f.close()
30     
31if __name__ == "__main__":
32    list_boottable("dsp_app.b00")

 

这段程序对一个设置为load-time的Boot Table的分析结果如下:

entry point: 0x2DFA6L   入口地址
register count: 1       寄存器设置个数
0x1c00 = 0x2210         寄存器设置
delay 0xffff , 0x100    延迟
0x7A20L <- 0x1ECCL bytes  复制0x1ecc个字节到地址0x7a20
0xF3C8L <- 0x98L bytes
0xF69CL <- 0xCL bytes
0xB0ECL <- 0x1696L bytes
0xF68CL <- 0x10L bytes
0xE688L <- 0x400L bytes
0x28430L <- 0x522CL bytes
0x2DD98L <- 0x27CL bytes
0x2E056L <- 0x6L bytes
0x2D65CL <- 0x73CL bytes
0x2E014L <- 0x42L bytes
0x3FF00L <- 0x100L bytes
0x1D9A4L <- 0x1FE2L bytes
0x5A20L <- 0x2000L bytes
0x17720L <- 0x6283L bytes  注意复制字节数为奇数
0xC782L <- 0x1503L bytes
0x2CFA00L <- 0x4L bytes    以下为对.cinit的展开
0x2CF800L <- 0x4L bytes    注意目标地址有问题
0x2D0A00L <- 0x4L bytes
0x766800L <- 0x4L bytes
.... 

从上面的结果可以看出,虽然Boot Table对.cinit段进行了展开,但是目标地址竟然是错误的。那么实际的地址应该是什么呢,用Coff Reader 打开out文件,查看.cinit段的数据,发现0x2CFA00所对应的地址应该是0x002CFA。那么只要修正这个目标地址的话,hex55所产生的那个Boot Table就可以正常使用了。

.cinit
------------------------------------------------
00 02 00 2c fa 00 44 7a 00 00 00 02 00 2c f8 00
44 7a 00 00 00 02 00 2d 0a 00 00 00 fa 00 00 02
00 76 68 00 00 00 75 44 00 02 00 76 6a 00 00 00 

还有一点需要注意:Boot Table中的目标地址是Byte地址,而.cinit中的地址是Word地址,因此必须把0x2CFA00转换为0x0059F4才对,也就是对有问题的地址(上面的0x2CFA00L, 0x2CF800L, 0x2D0A00L, 0x766800L等)右移7位就正确了。这个只需要稍微修改一下上面的那个Python程序就可以自动完成了。hex55居然有这么一个大BUG,有点令人难以置信,也许有什么参数可以让它产生正确的地址,不过自己动手解决这样的问题也是一种乐趣。


又去医院了

我摆的,怎么样?

这花可真香呀。 

昨天晚上发现海月身上有红点点,他爸爸说是湿疹,今天上午去医院一看,果真是湿疹。小孩子很容易得这个皮肤病,主要是对某种食物过敏。但也无需回避,要让她慢慢适应。今天在医院海月大哭起来,说什么也不肯到医生身边去。我说今天只是看看皮肤,才稍稍好了些。边看还边说,不看嗓子,不看嗓子。因为每次到医院都要看嗓子,这让她非常讨厌。


Karrigell的网络日志

最近想了解一下本网站的访问情况,google了一下,发现了一个不错的网络日志分析软件AWStats,它是用Perl编写的,先安装一个Perl的解释器就可以运行了。

下载下来运行一看,才发现Kerrigell的网络日志是简单版,没有User-Agent和Referer的记录。User-Agent提供很多客户端的信息,而Referer则记录页面的访问来源。通过分析这个访问来源,可以知道用户是通过搜索什么关键字找到本网站的,或者找到那些链接到本网站的网页。没有这两个信息的网络日志没有什么意思,而Karrigell似乎没有什么设置能够开启这两项的记录。于是只好修改它的代码了,分析了大半天,才发现只需要修改KarrigellRequestHandler.py文件中的以下函数的定义及即可。

01def log_message(self, format, *args):
02    try:
03        args = args[:2] + (self.RESPONSE.get("Content-Length", "-"),)
04    except:
05        pass
06    try:
07        referer = self.HEADERS.get("referer","-")
08        agent = self.HEADERS.get("user-agent","-")
09    except:
10        referer = "-"
11        agent = "-"
12    msg = ('%s - - [%s] %s "%s" "%s"' %
13                     (self.address_string(),
14                      self.log_date_time_string(),
15                      format%args, referer, agent))
16    if not k_config.silent:
17        BaseHTTPServer.BaseHTTPRequestHandler.log_message(self, format, *args)
18 
19    if k_config.loggingFile:
20        logging.info(msg)

修改了网络日志之后,分析了一下这两天的访问情况,发现除搜索引擎之外,有如下网站对本站进行了链接:

  • pazu是经常访问本站的一位搞嵌入式开发的朋友,他的博客有很多有趣的东西,发现了朋友的网站,真是一个不小的收获
  • 61ic则是盗贴了我所有的DSP文章的一个技术网站,他们没有把图片的链接修改过来,所以当用户阅读文章的时候,会从我的网站下载图片
  • imp3, applefans, aplbbs等网站都是链接的本站的rockbox的字库,看来这个字库还是挺受欢迎的
总数: 13 个不同的网页网页数百分比文件数百分比
http://pazu.512j.com/blog/blog.php428.5 %48.5 %
http://pazu.512j.com/xiaoyaoblog/214.2 %24.2 %
http://pazu.512j.com/bo-blog/index.php214.2 %24.2 %
http://pazu.512j.com/xiaoyaoblog/index.php17.1 %12.1 %
http://www.seeddsp.com/service/bbs/viewthread.php17.1 %12.1 %
http://bbs.imp3.net/thread-318963-1-1.html17.1 %12.1 %
http://applefans.cn/read.php17.1 %12.1 %
http://www.aplbbs.com/24296a1a317.1 %12.1 %
http://wiki.woodpecker.org.cn/moin/PlanetMe17.1 %12.1 %
http://www.61ic.com/Article/C6000/C67X/200802/19158.html  12.1 %
http://blog.woodpecker.org.cn/planet/  2757.4 %
http://www.61ic.com/Article/C6000/C67X/200802/19152.html  48.5 %
http://www.xianguo.com/reader/  12.1 %

见到老朋友了

 

猜我后面是什么?

上星期天我们的一个日本朋友来家里做客。海月出生后没回国的时候曾和他见过几次面,应该算是海月的老朋友了。这次海月来日本是第一次见他,两个人真的是一见如故。海月一下子就和他熟悉起来,他们一起唱歌,一起吃苹果。以至于海月坐在这位朋友的身上,叫他伯伯。我们看了都觉得非常惊奇。我的其它日本朋友来了,海月基本上只是打个照面就躲起来了。就是中国朋友来了也是远远地看着,不肯到跟前去。跟这位朋友来时所表现的反差太大了。就连我们回去接海月的时候也没有一下子就这么熟悉。我们都一致认为,海月一定还记得这位老朋友。
星期一正好有时间,我就把对门的母子三人请过来和海月玩,因为海月不肯去她们家了。海月和小男孩基本上是各玩各的,你说你的,我说我的。不过海月已经把他的名字记下来了,而且日语的请也说了多次,因为刚到我家时,小男孩不肯玩,海月极力推荐了各种玩具,总算渐渐活动起来。他们走后我问海月还让不让他们来玩,海月一会说让一会说不让,处在一种心理上的矛盾中。


超声波探伤系统

前两个月一直在忙超声波探伤系统的开发。它是为某个圆柱型钢材加工工厂的质量检测部门开发的系统。软件部分需要控制各种机械部件、电机、传感器,以完成自动超声波探伤。整个系统的构成相当复杂,程序需要从近30多个传感器获取数据,控制6个电机的运动,并且实时地从两块高速数据采集卡PCI-9812获取超声波数据,判断钢材中是否有缺陷,并绘制缺陷示意图。

在研究室里写完整个程序的基本结构,花了近一个月的时间。然后就出差到工厂里面实地调试了两个星期。在实际调试的时候才发现有许多东西并不是按照想像的那样运行,例如传感器可能出现误报;电机的Encoder信号可能出现噪声,以至于无法正确判断电机的位置;激光测距仪可能因为材料表面的反射条件而无法正确工作等等。而最令人头疼的是,工厂环境下的电气噪声和接触媒质(水)的不稳定会影响超声波探头的信号,使得缺陷反射的超声波信号和噪声混杂在一起,无法进行正确判断。看着搞装置的同事们想尽各种办法解决这些问题,我觉得我的实践经验值也突飞猛涨。将来有时间要好好写写这个系统开发过程中的经验教训。

客户对缺陷示意图的要求只要是2D的平面图就可以了。不过由于钢材是圆柱型的,平面图很难直观地表现缺陷的位置。于是我利用空闲时间用Python写了一个3D表现缺陷的小程序。下面是这个程序的界面截图,上方显示的是缺陷的平面图。可以看出平面图中蓝色区域标示了许多缺陷(红色的点),它们的实际位置在钢材的圆心部分,实际上是钢材中心的孔。

这个程序采用wxPython做界面,pyOpengl绘制3D图形,用wxPython的Plot模块绘制AScope(超声波的反射信号),用户可以用鼠标任意旋转、移动、放大缺陷,选中某个缺陷之后,可以详细查看其AScope波形,应该能为缺陷的人工检定带来不少的便利。



吃饭的乐趣

这两天基本上是在海月要饭吃的情况下,自己吃的饭。这样下去,吃饭不再是一个大难题,而是我的一个乐趣,看着她大口大口地吃着自己做的饭,会自然而然地产生一种成就感,还时不时地问她:好吃吗?似乎有点时间可以休息一下了,可是要做的事情还太多太多。总是在问自己日语怎么办呀,学的那点三脚猫的日语也已经忘的差不多了,可每当想学的时候又总是无法集中精力。
有的时候真的好想回家,呆在这里没有亲威没有朋友总是有一种慕名的孤独感。海月的教育问题也一直困扰着我们。可怎样才能回去呢,海月的爸爸回去要找什么样的工作,目前还完全没有头绪。我的日语也不足以让我以它来谋生。问题永远都会存在的,海月的成长却是无法阻当的。看着海月一天天象小树苗一样长大,还有什么比这更有成就感呢。

吃饭的问题

我要把泡泡吹到你的衣服上,把你的衣服搞脏。。。 

海月的吃饭问题其实一直困扰着我。上星期海月的爸爸提议要训练海月自己吃饭,至少不能再以中国式的填鸭方式喂海月了。其实多少次我都在和自己说,她不饿的时候不要喂饭,但做起来真的不容易,一到吃饭时间就想尽可能地让她多吃点,这无疑是一种错误的做法。我在对门的小男孩家看到:他只吃了几根面条后,他跟他的妈妈要,他的妈妈却一脸诧议地问:还要吃?由此可见我和他的妈妈之间的差距有多大了。
昨天开始我就采取了措施,不想吃坚决不喂饭。所以昨天中午基本上是海月自己吃的饭。晚上因为她一直不饿,但如果太晚了还不吃,那可能直接喝牛奶,所以我硬喂了几个饺子。今天中午喂了几口她就不想吃了,我也没有再喂,一直到现在海月还在睡觉,只有醒后让她自己吃了。如果吃饭的问题可以让她这样顺其自然地自己想吃就吃,那我真的可以轻松很多。


0 1