使用perl的“WWW::Mechanize”模块编写操作网页的自动化脚本
声明:这篇文章刚刚在飞测门户发过,作者都是我。
Perl的“WWW::Mechanize”模块可以实现对网页的多种操作,比如查找页面内的链接、内容、页面信息、填写表单、submit等功能,适合 用于网站的功能行测试,下面提供一个示例脚本:使用微软的必应引擎搜索"love"关键词,并在结果页面查找是否存在某一特定链接,在终端打印相应提示。 为了更完善地说明“WWW::Mechanize”模块的功能,脚本写得很罗嗦:
#! /usr/bin/perl # Author: ycjiang use 5.010; use warnings; use diagnostics; use WWW::Mechanize; # use URI; # use HTTP::Response; # use WWW::Mechanize::Link; use utf8; binmode(STDIN, ':encoding(utf8)'); binmode(STDOUT, ':encoding(utf8)'); binmode(STDERR, ':encoding(utf8)'); my $mech = WWW::Mechanize->new(); my $uri = 'http://www.cn.bing.com'; my $uri_hostname = 'cn\.bing\.com'; my $alias = 'Linux Mozilla'; my $agent = ${mech}->agent_alias($alias); my @links; my @links_samehost; my @forms; my $title = ''; # 确定客户端标识 $agent = ${mech}->agent_alias($alias); say("所支持的客户端标识:"); foreach (${mech}->known_agent_aliases()) { say($_); } say("当前客户端标识:".$agent); say(""); # 打开页面 eval { $mech->get($uri); }; say("当前处理的页面:".(${mech}->uri->as_string)); # say("正在刷新当前页面......"); # $mech->reload(); # 调用reload方法不会修改浏览历史 if (! ${mech}->success) { die("Oops! 打开页面 \"".(${mech}->uri->as_string)."\" 失败: ".(${mech}->res->status_line)); } else { say("成功打开页面 \"".(${mech}->uri->as_string)."\" 状态码: ".(${mech}->status)); } say(""); # 网页头 $title = ${mech}->title; say("网页头: ", $title); say(""); # 网页中的链接 @links = ${mech}->links; say("页面中存在的所有链接:"); foreach (@links) { if(${_}->text) { print("\"", ${_}->text, "\" 的URL为: "); } else { print("\"undefined\" 的URL为: "); } if(${_}->url =~ m/^\//) { say(${mech}->uri->as_string.${_}->url); } elsif (${_}->url =~ m/^\?/) { say(${mech}->uri->as_string.'/'.${_}->url); } else { say(${_}->url); } } say(""); # 页面上的可显示文本: say("页面上的可显示文本:"); say(${mech}->content(format => 'text')); say(""); # 查看是否存在某一链接: say("页面上可以找到的第五个链接为: ".$mech->find_link(n => 5)->url); say("页面上可以找到的与本页面在同一域名的链接为: "); foreach (@links) { if(${_}->url =~ m/(^\/)|(^\?)|(^http.{3,4}(www){0,1}${uri_hostname})/) { print(${_}->url); push(@links_samehost, ${_}->url); if(${_}->text) { say(": ",${_}->text); } else { say(": undefined"); } } } say(""); # 表单操作: # @forms=$mech->forms; say("表单操作: "); $mech->form_id('sb_form'); $mech->field('q', 'love'); say("在搜索框内填写了单词\"love\""); $mech->submit(); say("点击搜索..."); say("现在正在处理的网页地址为: "); say(${mech}->uri->as_string); # say("此时页面上的可显示文本为:"); # say(${mech}->content(format => 'text')); say("在页面上查找指定的链接(http://baike.baidu.com/view/4409.htm, 百度百科的love词条),查找结果为:"); if($mech->find_link(url_regex=>qr/baike\.baidu\.com\/view\/4409\.htm/)){ say("找到了"); } else { say("未找到"); } say("");
LFS-7.1安装笔记, 'devtmpfs filesystem问题'
系统安装完成, 重启, 可是内核挂载虚拟文件系统‘/dev’时提示错误:
’error unknown filesystem type devtmpfs‘.
只好再次重启, 回到寄主系统中排查错误。看到文件/etc/fstab中有一行:
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0
内核在挂载这一文件系统时出错, google后才知道, 配置内核时还需要手动选择'devtmpfs filesystem'的支持:
Device Drivers --->
Generic Driver Options --->
Maintain a devtmpfs filesystem to mount at / dev
重新编译内核, 重启, 问题解决.
这似乎是在LFS-7.1中加入的新特性,不过手册中没有说清楚。
原帖地址:https://answers.launchpad.net/lfscript/+question/186427
汉诺塔的递归实现
汉诺塔问题简介: http://zh.wikipedia.org/wiki/%E6%B1%89%E8%AF%BA%E5%A1%94
其递归实现的函数原型为: 'void hanoi(int n, char a, char b, char c);'. 其中字符变量'a', 'b', 'c'分别表示从杆子a, 杆子b, 杆子c, 整数变量'n'表示汉诺塔问题的阶数(即杆子a上有n个待移动到杆子c的圆盘, 杆子b作为临时杆子).
其递归实现的步骤为:
1. 如果n==1, 则直接将唯一的圆盘从杆子a移动到杆子c, 问题解决.
2. 否则, 将杆子a上的(n-1)个圆盘移动到杆子b(通过递归实现),
然后将杆子a上剩余的最大的圆盘移动到杆子c,
最后将杆子b上的(n-1)个圆盘移动到杆子c(通过递归实现), 问题解决.
其递归实现的C代码为:
#include<stdio.h> void hanoi(int, char, char, char); int main(void) { int n=3; printf("输入数字n:\n"); scanf("%d", &n); hanoi(n, 'A', 'B', 'C'); return 0; } void hanoi(int n, char a, char b, char c) { if(n==1) { printf("%c->%c\n", a, c); } else { hanoi(n-1, a, c, b); printf("%c->%c\n", a, c); hanoi(n-1, b, a, c); } }
之前在笔试中遇到的, 记录一下.
C 数据类型转换
看一下段代码, 分析for循环的循环体会执行多少次:
#include<stdio.h> int main(void) { int i; for(i=-1; i < sizeof(int); i++) { printf("%d, ", i); } return 0; }
实验表明, 在不同的编译器下, 这个循环的实现也不一样:
1. 在gcc下, 由于'sizeof(int)'的返回值是'unsigned long int'类型的, 但'i'的类型是'signed int'类型的, 二者在做比较时要将i从'signed int'转换成'unsigned long int', 但由于i原来是有符号的'-1', 转换后变为无符号的'0xffffffff', 当然比'sizeof(int)'大, 结果for循环体一次也没有执行.
2. 在Turbo C下, 由于'sizeof(int)'的返回值是'signed int'类型的(注意: 这不符合C标准的规定), 所以与'i'比较是没有类型转换, for循环体会执行5次.
严重注意: 有些东西了解就行, 以便在出现问题时知道如何解决, 但尽量不要在自己的代码中尝试那些东西.
C语言 char型也是分有符号数和无符号数的
unsigned char型表示无符号数, 取值范围是 0~255.
signed char型表示无符号数, 取值范围是 -128~127.
在x86平台上, gcc规定不带'unsigned'或'signed'关键字的char是有符号的. 参见以下代码 :
#include<stdio.h> int main(void) { printf("(signed char)200: %d\n", (signed char)200); printf("(unsigned char)200: %d\n", (unsigned char)200); printf("(char)200: %d\n", (char)200); // gcc定义char型是有符号的。 return 0; }
打印结果为:
(signed char)200: -56
(unsigned char)200: 200
(char)200: -56
利用objdump工具对其进行反汇编, 观察向printf函数传递的第二个参数, 节选部分汇编代码:
printf("(signed char)200: %d\n", (signed char)200);
80483cd: b8 e0 84 04 08 mov $0x80484e0,%eax
80483d2: c7 44 24 04 c8 ff ff movl $0xffffffc8,0x4(%esp)
80483d9: ff
80483da: 89 04 24 mov %eax,(%esp)
80483dd: e8 12 ff ff ff call 80482f4 <printf@plt>
printf("(unsigned char)200: %d\n", (unsigned char)200);
80483e2: b8 f6 84 04 08 mov $0x80484f6,%eax
80483e7: c7 44 24 04 c8 00 00 movl $0xc8,0x4(%esp)
80483ee: 00
80483ef: 89 04 24 mov %eax,(%esp)
80483f2: e8 fd fe ff ff call 80482f4 <printf@plt>
printf("(char)200: %d\n", (char)200); // gcc定义char型是有符号的。
80483f7: b8 0e 85 04 08 mov $0x804850e,%eax
80483fc: c7 44 24 04 c8 ff ff movl $0xffffffc8,0x4(%esp)
8048403: ff
8048404: 89 04 24 mov %eax,(%esp)
8048407: e8 e8 fe ff ff call 80482f4 <printf@plt>
还有一个问题需要注意, 从汇编代码可以看到, 实际上用了四个字节存储char类型的参量, 即: 像printf这种形参类型未知的函数, 调用函数时编译器会自动对相应的实参做Integer Promotion.