【 Perl 】控制Firefox实现自动化Web测试

安装

1、安装Firefox插件

git clone git://github.com/bard/mozrepl
cd mozrepl
zip -r ../mozrepl.zip *
cd ..
mv mozrepl.zip mozrepl.xpi

2、安装Perl模块

cpanm WWW::Mechanize::Firefox
cpanm HTML::Display::Common

3、启动插件
先打开Firefox;
然后Firefox -> 工具 -> MozRepl -> Start

4、开始写程序控制你的Firefox吧

一个简单的例子

以打开新浪首页为例。

use WWW::Mechanize::Firefox;
my $mech = WWW::Mechanize::Firefox->new( autoclose => 0, activate => 1 );
$mech->get('http://sina.com.cn');

一个稍复杂的例子

让Firefox自动打开百度首页
1、在终端上输出页面title;
2、在浏览器中搜索一个词”perl”。

use strict;
use warnings;

use WWW::Mechanize::Firefox;
binmode STDOUT, ':utf8';

my $mech = WWW::Mechanize::Firefox->new( autoclose => 0, activate => 1 );
$mech->get('http://baidu.com');
print $mech->title();
$mech->form_name( "f" );
$mech->set_fields( "wd", "perl" );
$mech->submit;

效果如这个视频所示

v.youku.com/v_show/id_XNzU3MTY2NTg4.html

抽取某条微博的全部评论

#!/usr/bin/perl
use strict;
use warnings;

use WWW::Mechanize::Firefox;
use utf8::all;
use File::Slurp;
use JSON::XS;
use Encode;
use URL::Encode qw(url_decode_utf8 url_decode);
use Data::Dump qw(ddx);

my $mech = WWW::Mechanize::Firefox->new( autoclose => 1, activate => 1 );
my $url = 'http://weibo.com/aj/comment/big?_wv=5&id=3744295209134458&max_id=3744609358765392&filter=0&__rnd=1408272337687';
for ( 1 .. 42)
{
	$mech->get( "$url&page=$_" );
	my $a = encode( 'utf8', $mech->content( raw => 1 ));
	$a =~ s/.*?//g;
	$a =~ s/<\/prre><\/body><\/html>//g;
	#print $a;

	my %b = %{decode_json $a};
	my $c = $b{'data'}{'html'};
	$c =~ s/\n//smg;
	$c =~ s/\s+/ /smg;
	$c =~ s/>/>/smg;
	$c =~ s/</.*?<\/a>:.*?)/smg;
	foreach (@abc)
	{
		my ($name, $words) = $_ =~ /usercard="id=\d+">(.*?)<\/a>:(.*?)/;
		$name =~ s/<\/a>//g;
		$name =~ s///g;
		$words =~ s/<\/a>//g;
		$words =~ s///g;
		$words =~ s///g;
		print "$name => $words\n";
	}
}

相关文档

WWW::Mechanize https://metacpan.org/pod/WWW::Mechanize
WWW::Mechanize::Firefox https://metacpan.org/pod/WWW::Mechanize::Firefox
WWW::Mechanize::Firefox::Examples https://metacpan.org/pod/WWW::Mechanize::Firefox::Examples
WWW::Mechanize::Firefox::Cookbook https://metacpan.org/pod/distribution/WWW-Mechanize-Firefox/lib/WWW/Mechanize/Firefox/Cookbook.pod

和QTP、WinRunner、Selenium相比看看,Perl确实让这件事变得简单些了。

【 Perl 】三种方式解决” Wide character in subroutine/print “

1、binmode STDOUT, “:utf8″;

因为程序本身是用utf8编码的(可以用use utf;明示给Perl)。
这句话就是告诉Perl输出是utf8编码的。

2、use utf8::all;

当然,我们需要先安装这个模块 utf8::all
一劳永逸,所有涉及字符集编码的地方,此模版都会帮你设置为utf8;

3、encode( ‘utf8′, $_ );

嗯。需要先use Encode;。
对CPU有不小的开销。
这种处理方法的好处在于可以用于print之外的其它方法出现的”Wide character in subroutine”问题。管得比较宽。

4、原因

宽字节这事,是从windows C++发祥的。
我理解是懒得认真处理字符集问题的一种偷懒方式。将多个字节绑定为单一结构体内,以期达到hack式修复的目的。
这种做法确实使得在VS上编程时不用关心字符集了。
效果嘛,只能说在windows内部自己玩的时候还算蛮不错……

Redis服务器的sysctl.conf配置

调整思路

  1. 减少Linux系统自身,特别是IO系统对内存的使用,避免在内存上与Redis冲突;
  2. Redis的Dump动作是一个大型IO动作,为避免Dump冲击系统,将其触发的尖峰写操作适当削平成一个持续的写操作;
  3. 尽量让tcp栈保持干净;

参数选择理由

#0 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
#1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
#2 表示内核允许分配超过所有物理内存和交换空间总和的内存
#我们设置为1,表示尽量给Redis内存,但不要把硬盘当内存分配给它。
#这是redis官方要求必须配置的选项。

vm.overcommit_memory = 1

#这个参数控制文件系统的文件系统写缓冲区的大小,单位是百分比,表示系统内存的百分比,表示当写缓冲使用到系统内存多少的时候,开始向磁盘写出数据。增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当你需要持续、恒定的写入场合时,应该降低其数值,:

vm.dirty_ratio = 1

#这个参数控制文件系统的pdflush进程,在何时刷新磁盘。单位是百分比,表示系统内存的百分比,意思是当写缓冲使用到系统内存多少的时候,pdflush开始向磁盘写出数据。增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当你需要持续、恒定的写入场合时,应该降低其数值,

vm.dirty_background_ratio = 1

#这个参数控制内核的脏数据刷新进程pdflush的运行间隔。单位是 1/100 秒。缺省数值是500,也就是 5 秒。如果你的系统是持续地写入动作,那么实际上还是降低这个数值比较好,这样可以把尖峰的写操作削平成多次写操作。设置方法如下

vm.dirty_writeback_centisecs = 100

#这个参数声明Linux内核写缓冲区里面的数据多“旧”了之后,pdflush进程就开始考虑写到磁盘中去。单位是 1/100秒。缺省是 30000,也就是 30 秒的数据就算旧了,将会刷新磁盘。对于特别重载的写操作来说,这个值适当缩小也是好的,但也不能缩小太多,因为缩小太多也会导致IO提高太快。

vm.dirty_expire_centisecs = 100

#该文件表示系统进行交换行为的程度,数值(0-100)越高,越可能发生磁盘交换。
#我们设置为0,表示不要进行swap

vm.swappiness = 10

#该文件表示内核回收用于directory和inode cache内存的倾向;缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache;增加该值超过100,将导致内核倾向于回收directory和inode cache

vm.vfs_cache_pressure = 110

#1 To free pagecache:
#2 To free reclaimable slab objects (includes dentries and inodes):
#3 To free slab objects and pagecache:
#经过实验,此选项只在设置那一次会生效释放掉内存,此后IO占用的内存还会持续增长
#且再次执行sync也不释放,只有再次设置此选项才会再次释放,因此我们选择不设置此项

#vm.drop_caches = 3

#64位系统所有内存都被划分为lowmem,无需此项配置

#vm.lowmem_reserve_ratio = 32 32 8

#FreeBSD参数

#kern.maxvnodes = 3

#zone_reclaim_mode在内核默认就是禁用的。
#mongodb明确要求在NUMA系统上禁用此选项
#内核文档中说到如果打开此选项,NUMA节点在访问远端内存时会遭遇严重的性能问题。要求只在完全可以handle数据(cpu cache)位置时才调整此选项

vm.zone_reclaim_mode = 0

最终使用的配置

以下是一个64位的Linux-Redis服务器的最终sysctl.conf优化配置。
包括了 百次掉坑一朝总结之net.ipv4参数 中介绍的关于网络连接的优化配置。

#maximize the available memory
vm.overcommit_memory = 1
vm.dirty_ratio = 1
vm.swappiness = 10
vm.vfs_cache_pressure = 110
vm.zone_reclaim_mode = 0

#keep the IO performance steady
vm.dirty_background_ratio = 1
vm.dirty_writeback_centisecs = 100
vm.dirty_expire_centisecs = 100

#keep the tcp stack clean
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 1024    65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000

参考文档

kernel.org的sysctl官方文档 https://www.kernel.org/doc/Documentation/sysctl/

freebsd官方内核调整建议 http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/configtuning-kernel-limits.html

linux服务器lowmem不足引起系统崩溃的解决 http://blog.csdn.net/i3myself/article/details/8663801

淘宝内核维基 http://kernel.taobao.org/index.php/Kernel_Documents/mm_sysctl

磁盘读写参数设置 http://hi.baidu.com/roxws/item/4fb9fe2c368fdbd00e37f9e9

mongodb的NUMA问题 http://www.ttlsa.com/mongodb/mongodb-numa/

百次掉坑一朝总结之net.ipv4参数


#最小化连接数
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1 #会导致NAT内网某些用户的连接问题,与tcp_timestamps共同作用
net.ipv4.ip_local_port_range = 1024    65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000

#防止ip_conntrack爆掉
net.ipv4.netfilter.ip_conntrack_tcp_timeout_max_retrans = 120
net.ipv4.netfilter.ip_conntrack_max = 655360 

#接受组播流
net.ipv4.conf.eth0.rp_filter = 0 

#内存回收模式(某个zone内存不够时尝试gc)
vm.zone_reclaim_mode = 0 #多核机器建议设置为0

故障,真是一件让人心塞的事。

【 2014每月一模块 】URI::URL::AddQueryParam组装URL

URI::URL::AddQueryParam 这个模块主要用于在HTTP回调的时候增加GET参数。自动进行一些特殊的字符的处理,而且避免出现这样的代码:

if ($url =~ /?/ ) 
{
  $url .= "&" . $k . "=" . $v;
}
else
{
  $url .= "?" . $k . "=" . $v;
}

用法如下:

use URI::URL::AddQueryParam qw(http_add_query_param);
 
my %http_param = ('ta' => 'ok', 'foobar' => 1, 'hoge' => 0);
my $base_url = 'http://example.com/';
print http_add_query_param($base_url, \%http_param);
# got 'http://example.com/?ta=ok&hoge=0&foobar=1'
 
%http_param = ('ta' => 'ok', 'foobar' => 1, 'hoge' => 0);
$base_url = 'http://example.com?soso=gogo';
print http_add_query_param($base_url, \%http_param);
# got 'http://example.com/tt3.php?soso=gogo&ta=ok&hoge=0&foobar=1'

软件开发方法论的二十六篇经典

短文奉上原文和译文地址,书籍则附上豆瓣读书的地址以便购买。
尽量为所有的读物都附上了维基条目,没有维基的附上作者的介绍,方便了解写作背景。

豆列请戳这里

1. 文章 1968 《Goto语句有害》 中文译文 英文原文 中文维基 英文维基
2. 书籍 1968 《计算机程序设计艺术》 豆瓣读书 Google图书 中文维基 英文维基
3. 书籍 1971 《程序开发心理学》 豆瓣读书 Google图书 n/a 英文维基
4. 文章 1972 《谦卑的程序员》图灵奖获奖演讲 中文译文 英文原文 中文维基 英文维基
5. 书籍 1975 《人月神话》 豆瓣读书 Google图书 中文维基 英文维基
6. 书籍 1979 《哥德尔、艾舍尔、巴赫》 豆瓣读书 Google图书 中文维基 英文维基
7. 书籍 1981 《计算机编程科学》 豆瓣读书 Google图书 n/a 英文维基
8. 书籍 1982 《追求卓越》 豆瓣读书 Google图书 中文维基 英文维基
9. 文章 1985 《战略防御系统的软件部分》 n/a 英文原文 n/a n/a
10. 文章 1986 《没有银弹》 n/a 英文原文 中文维基 英文维基
11. 书籍 1989 《软件失控》 豆瓣读书 Google图书 n/a 英文维基
12. 书籍 1994 《如何避免被计算机伤害》 亚马逊 Google图书 n/a n/a
13. 文章 1994 《不成熟的CMM》 n/a 英文原文 中文维基 英文维基
14. 文章 1996 《软件设计宣言》 n/a 英文原文 n/a n/a
15. 书籍 1997 《死亡之旅》 豆瓣读书 Google图书 n/a 英文维基
16. 文章 1997 《大教堂和市集》 豆瓣读书 繁体译文 中文维基 英文维基
17. 书籍 1999 《软件的极限》 豆瓣读书 Google图书 n/a n/a
18. 书籍 1999 《软件创新之路》 豆瓣读书 Google图书 中文维基 英文维基
19. 书籍 2000 《软件阴谋》 豆瓣读书 Google图书 n/a n/a
20. 文章 2001 《敏捷宣言》 中文译文 英文原文 中文维基 英文维基
21. 书籍 2001 《Getting Things Done》 豆瓣读书 Google图书 中文维基 英文维基
22. 文章 2002 《设计决策》 n/a 英文原文 n/a n/a
23. 书籍 2004 《黑客与画家》 豆瓣读书 Google图书 中文维基 英文维基
24. 书籍 2004 《苹果往事》 豆瓣读书 Google图书 n/a 英文维基
25. 书籍 2004 《Joel说软件》续篇《软件随想录 豆瓣读书 Google图书 中文维基 英文维基
26. 书籍 2007 《梦断代码》 豆瓣读书 Google图书 n/a 英文维基

【 2014每月一模块 】Word::Segmenter::Chinese::Lite中文分词

前段时间给聊天室写叶贝斯过滤的时候,发现CPAN上居然没有中文分词模块。
好吧,我来贡献一个。
支持一元分词,二元分词,词典分词。
词典是内嵌的。不用大家去找了。

地址在此:Word::Segmenter::Chinese::Lite

用法依然简单:


use Word::Segmenter::Chinese::Lite qw(wscl_seg wscl_set_mode);

# 默认使用词典分词 
my @result = wscl_seg("中华人民共和国成立了oyeah");
foreach (@result)
{
  print $_, "\n";
}
# got:
# 中华人民共和国
# 成立
# 了
# oyeah
 
# 交叉二元分词
wscl_set_mode("obigram");
my @result = wscl_seg("中华人民共和国成立了");
foreach (@result)
{
  print $_, "\n";
}
# got:
# 中华
# 华人
# 人民
# 民共
# 共和
# 和国
# 国成
# 成立
# 立了
# 了
 
# 一元分词
wscl_set_mode("unigram");
my @result = wscl_seg("中华人民共和国");
foreach (@result)
{
  print $_, "\n";
}
# got:
# 中
# 华
# 人
# 民
# 共
# 和
# 国

关于分词本身,没啥可说的,这次扯两句闲篇吧。

现在ES很火,以前lucene很火。其实多对于很小应用(比如说我们4000万日PV网站的搜索)来说,它们都过于杀鸡牛刀了。自己实现其实更加轻松写意。
最关键的是,牛刀在大多数时候,并杀不好鸡。

曾经GFS很火,现在golang又很火,凡是Google挺的东西都会很火。
曾经lucene很火,现在hadoop又很火,Doug Cutting的东西都会很火。
其实我想说lucene的实现并不咋地,性能也相当一般。
GFS在为我们所知的时候其实也就那样。Google放论文出来时,那架构已经并不先进了。
过两年,Google自己就放弃GFS了。可一堆舔臭脚的还在玩命捧。
现在的hadoop其实也一样。

我就不明白,干嘛总会有所谓“热门的技术”。
这些技术的火爆,到底是因为真的精准命中所有人的业务,还是因为Google和Apache主席双重爆点导致的呢?
干嘛总会有“用xxx软件就是所有人干xxx事不约而同的解法”。
难道咱们的世界里,需求同质化真有如此严重?

我就很烦这些事。其实太多东西有更简单解法。

以上就是今天凑字数的内容。

【 Perl 】序列化方法横向简评

以下模块是经测评后,每种序列化方法中速度最快的。
如:测试YAML::Syck和YAML::XS,后者比前者快,所以只列出后者。

JSON::XS

反序列化速度: 0.41 secs
序列化数据大小:3.6 M
序列化数据描述:一个大单行无二进制的字符串
主观评价:性能最优。但是大单行用vim处理起来压力略大。

Storable

反序列化速度:0.45 secs
序列化数据大小:4.1 M
序列化数据描述:包含二进制数据
主观评价:二进制数据不太方便手动修改和阅读

PHP::Serialization::XS

反序列化速度:1.55 secs
序列化数据大小:5.3 M
序列化数据描述:模样很像JSON,也是个大单行。但因描述数据的类型,比JSON大很多。
主观评价:平庸,速度略慢

YAML::XS

反序列化速度:2.08 secs
序列化数据大小:3.8 M
序列化数据描述:自带分行的非二进制数据,在n多分行符的前提下依然做到了第二名的体积,厉害。
主观评价:唯一一个序列化出来的字符自带分行的,这样vim编辑的时候压力很小。可惜反序列化速度实在有点慢。

Data::Dumper & Data::Dump

反序列化速度:3.28 secs
序列化数据大小:13 M
序列化数据描述:非二进制数据,也是分行的。但是中文会用’\x{56c1}’的形式表达。
主观评价:虽然使用是最最方便的,但速度实在太慢。

Google::ProtocolBuffers

反序列化速度:n/a
序列化数据大小:n/a
序列化数据描述:包含二进制数据
主观评价:不能任意序列化对象,需预定义数据结构。

Storable::AMF0 & Storable::AMF3

反序列化速度:n/a
序列化数据大小:n/a
序列化数据描述:包含二进制数据
主观评价:此模块年久失修

XML::Bare

反序列化速度:n/a
序列化数据大小:n/a
序列化数据描述:XML不用多说了
主观评价:

1、不能任意序列化对象,无初始化方法。
2、此模块虽然也有序列化功能,但更偏向反序列化。

【 2014每月一模块 】【MaxMind::DB::Writer::FromTextFile】打包MaxMind格式的IP库

猛一抬头,5月都快过完了。这个月里有三天用来写了个Varnish扩展,根据来源IP查所在地。

之前我们是用nginx的geo模块做的,这个插件能帮助我们去掉nginx这个组件,从而提高性能也减少句柄数。

调研时发现了以下情况:

1、GeoIP已经升级到了第二代。存储格式改名叫了MaxMindDB,C的API也从libgeoip改成了libmaxminddb;

2、分别用libgeoip和libmaxminddb的默认模式写了两个例程。单次查询前者耗时20ms,后者耗时2ms。新版性能优势明显;

3、它们有读文件模式,也有共享内存模式。

见过几个查IP的数据结构和算法实现,包括公司自己用的和一些其它公开的SDK。自己也曾实现过。

各方面libmaxminddb都是我眼界中最好的。果断基于它来实现Varnish扩展。

那么剩下的问题就是,如何把自己的IP库打包MaxMindDB格式。人家的IP库是收费的,而且就算买了,也不可能说就放弃修改之的能力。

所以本月的模块就是给Perl提供将文本格式的IP库打包成MaxMindDB的能力。

模块地址在此https://metacpan.org/pod/MaxMind::DB::Writer::FromTextFile。用法一如既往的简单。

use MaxMind::DB::Writer::FromTextFile;
mmdb_create($input_filename, $output_mmdb_filename);

其实MaxMind公司在Github上是托管了一个写MMDB格式的代码的,而且正是基于Perl的。本模块也依赖那代码。那代码坑挺多的,对环境的要求略严苛。编译的过程中给我找了不少麻烦。不知是不是因为这个原因没有发布到CPAN,我把这个模块传到CPAN后他们还给我发信要求我把namespace留给他们……希望他们可以尽快把代码整理好发布到CPAN吧。如果MaxMind迟迟没有行动的话,也许后面几个月,我还能再交一个关于他们的CPAN作业呢。^_^

好消息是,MaxMind公司已经把MaxMind::DB::Writer发布到了CPAN。

下期预告

前段时间做聊天过滤的时候发现CPAN上居然没有中文分词模块。

六月的作业我会把之前写的中文分词代码整理一下交上来。