PHP的SSH2扩展的安装(基于linux(centos))

 首先要确保系统已经安装好了(LNMP或者LAMP,具体的安装方式见地址

1.编译安装libssh2



wget http://www.libssh2.org/download/libssh2-1.2.9.tar.gz
tar zxvf libssh2-1.2.9.tar.gz
cd libssh2-1.2.9
./configure&&make&&make install



2.编译安装ssh2(官网http://www.php.net/ssh2)



wget http://pecl.php.net/get/ssh2-0.11.2.tgz
tar zxvf ssh2-0.11.2.tgz
cd ssh2-0.11.2
phpize(如果没有找到该命令,请确定是否安装的是php-dev)
./configure --with-ssh2 --with-php-config=/usr/local/php/bin/php-config
make
cp modules/ssh2.so /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/
echo "extension=ssh2.so" >> /etc/php.ini

 

 

阅读全文 »

python构造复杂的C结构体(用于网络通信UDP、TCP)

python提供了丰富的内置类型:比如字符串,整数,浮点数,列表,元组,字典,但是没有提供类似C语言的结构体类型,如果我们用python来实现客户端,用C来是实现服务器的话,需要用python来实现C的结构体,并且用UDP或者TCP传输。 python中的struct模块专门用来处理python的值和C的类型结构之间的转换 , 此模块执行 的Python Python字符串 表示 的 值 和 C的结构 之间 的 转换 。 这可以用来 处理 的二进制数据 存储 在文件或 网络连接 , 以及其他 来源 。 struct模块主要的方法有三种pack、unpack、calcsize: struct.pack(fmt,v1,v2,.....) 将v1,v2等参数的值进行包装,包装的方法由fmt指定,被包装的参数必须严格符合fmt,最后返回字符串。 struct.unpack(fmt,string) 返回一个由解包数据(string)得到的一个元组(tuple)。 struct.calcsize(fmt),用来计算fmt格式所描述的结构的大小,也等于len(string)。 下面来介绍一下fmt(格式字符串格式): 默认情况下, C类型 的代表 在 机器的 原生格式 和 字节顺序 , 如果 必要的 (按 C编译器 所 使用 的 规则 ) 跳过 填充字节, 正确 对齐 。 此外, 格式字符串的 第一个字符 ,可以 用来 表明 字节顺序 ,大小和 压缩数据 的 对齐 , 根据 下表 :(默认情况是不加,实际上是按照@要求表示字节顺序以及字节,对齐) Character Byte order Size Alignment @ native native native = native standard none little-endian standard none big-endian standard none ! network (= big-endian) standard none 格式字符串除了上表的第一个字符外,还支持一下格式: Format C Type Python type Standard size Notes x pad byte no value c char string of length 1 1 b signed char integer 1 (3) B unsigned char integer 1 (3) ? _Bool bool 1 (1) h short integer 2 (3) H unsigned short integer 2 (3) i int integer 4 (3) I unsigned int integer 4 (3) l long integer 4 (3) L unsigned long integer 4 (3) q long long integer 8 (2), (3) Q unsigned long long integer 8 (2), (3) f float float 4 (4) d double float 8 (4) s char[] string p char[] string P void * integer (5), (3) 例子:直接使用library上的例子 from struct import * pack ( 'hhl' , 1 , 2 , 3 ) 包装 'x00x01x00x02x00x00x00x03' unpack ( 'hhl' , ' x00x01x00x02x00x00x00x03 ' ) 解包 (1, 2, 3) calcsize ( 'hhl' ) 8 最后来讲一下关键的问题:如何使用python来模拟C的结构体? 首先来看C的结构体如下面的形式: struct info { int age; float score; char name1[3]; }; typedef struct my_data { char name[10]; struct info test; } MY_DATA; 如果用python来进行包装的话,可以使用下面的形式: name = sleetdrop age = 28 score = 1000 name1= aes info = struct.pack( 10sif3s , name,age, score, name1) 最后看看用python写的客户端,用C写的服务器,用UDP传输信息。 python代码:(ip地址和端口号根据自己需要更改) import socket, struct serviceip = "10.0.0.28" port = 3000 name = "sleetdrop" age = 28 score = 1000 name1="aes" info = struct.pack("10sif3s", name,age, score, name1) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(info, (serviceip, port)) C的代码: #include #include #include #include #include #include #include #include struct info { int age; float score; char name1[3]; }; typedef struct my_data { char name[10]; struct info test; } MY_DATA; void dg_echo(int, struct sockaddr *, socklen_t); int main(int argc, char **argv) { int sockfd; struct sockaddr_in svraddr, cliaddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero( svraddr, sizeof(svraddr)); svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = htonl(INADDR_ANY); svraddr.sin_port = htons(3000); bind(sockfd, (struct sockaddr *) svraddr, sizeof(svraddr)); dg_echo(sockfd, (struct sockaddr *) cliaddr, sizeof(cliaddr)); } void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) { int n; socklen_t len; MY_DATA mydata ...

阅读全文 »

python quiz 47-71

Q47: names1 = ['Amir', 'Barry', 'Chales', 'Dao'] names2 = names1 names3 = names1[:] names2[0] = 'Alice' names3[1] = 'Bob' sum = 0 for ls in (names1, names2, names3): if ls[0] == 'Alice': sum += 1 if ls[1] == 'Bob': sum += 10 print sum 11 12 21 22 33 Q48: names1 = ['Amir', 'Barry', 'Chales', 'Dao'] loc = names1.index( Edward ) print loc -1 0 4 Edward An exception is thrown Q49: names1 = ['Amir', 'Barry', 'Chales', 'Dao'] if 'amir' in names1: print 1 else: print 2 1 2 An exception is thrown Q50: names1 = ['Amir', 'Barry', 'Chales', 'Dao'] names2 = [name.lower() for name in names1] print names2[2][0] i a c C An exception is thrown Q51: numbers = [1, 2, 3, 4] numbers.append([5,6,7,8]) print len(numbers) 4 5 8 12 An exception is thrown Q52: list1 = [1, 2, 3, 4] list2 = [5, 6, 7, 8] print len(list1 + list2) 2 4 5 8 An exception is thrown Q53: def addItem(listParam): listParam += [1] mylist = [1, 2, 3, 4] addItem(mylist) print len(mylist) 1 4 5 8 An exception is thrown Q54: my_tuple = (1, 2, 3, 4) my_tuple.append( (5, 6, 7) ) print len(my_tuple) 1 2 5 7 An exception is thrown Q55: a = 1 b = 2 a,b = b,a print %d %d % (a,b) 1 2 2 1 An exception is thrown This program has undefined behavior Q56: def print_header(str): print +++%s+++ % str print_header.category = 1 print_header.text = some info print_header( %d %s % (print_header.category, print_header.text)) +++1 some info+++ +++%s+++ 1 1 some info Q57: def dostuff(param1, *param2): print type(param2) dostuff('apples', 'bananas', 'cherry', 'dates') str int tuple list dict Q58: def myfunc(x, y, z, a): print x + y nums = [1, 2, 3, 4] myfunc(*nums) 1 3 6 10 Q59: class A: def __init__(self, a, b, c): self.x = a + b + c a = A(1,2,3) b = getattr(a, 'x') setattr(a, 'x', b+1) print a.x 1 2 3 6 7 Q60: class NumFactory: def __init__(self, n): self.val = n def timesTwo(self): self.val *= 2 def plusTwo(self): self.val += 2 f = NumFactory(2) for m in dir(f): mthd = getattr(f,m) if callable(mthd): mthd() print f.val 2 4 6 8 an exception is thrown Q61: one = chr(104) two = chr(105) print %s%s % (one, two) hi h Inside the mytools dir create a __init__.py and myparser.py 104105 104 Q62: x = 0 y = 1 a = cmp(x,y) if a x: print a elif a == x: print b else: print c a b c Q63: x = 1 y = 2 z = 3 sum = 0 for i in (x,y,z): if isinstance(i, int): sum += i print sum 2 3 4 6 Q64: x = sum(range(5)) print x 4 5 10 15 Q65: def getinput(): print 0: start print 1: stop print 2: reset x = raw_input( selection: ) try: num = int(x) if num 2 or num 0: return None return num except: return None num = getinput() if not num: print invalid else: print valid valid invalid An exception is thrown Q66: kvps = { '1' : 1, '2' : 2 } theCopy = kvps kvps['1'] = 5 sum = kvps['1'] + theCo ...

阅读全文 »

python quiz 25-46

Q25: name = snow storm print %s % name[6:8] st sto to tor Syntax Error Q26: name = snow storm name[5] = 'X' print name snow storm snowXstorm snow Xtorm ERROR, this code will not run Q27: for i in range(2): print i for i in range(4,6): print i 2, 4, 6 0, 1, 2, 4, 5, 6 0, 1, 4, 5 0, 1, 4, 5, 6, 7, 8, 9 1, 2, 4, 5, 6 Q28: values = [1, 2, 1, 3] nums = set(values) def checkit(num): if num in nums: return True else: return False for i in filter(checkit, values): print i 1 2 3 1 2 1 3 1 2 1 3 1 2 1 3 1 1 1 1 2 2 3 3 Syntax Error Q29: values = [2, 3, 2, 4] def my_transformation(num): return num ** 2 for i in map(my_transformation, values): print i 2 3 2 4 4 6 4 8 1 1.5 1 2 1 1 1 2 4 9 4 16 Q30: import pickle class account: def __init__(self, id, balance): self.id = id self.balance = balance def deposit(self, amount): self.balance += amount def withdraw(self, amount): self.balance -= amount myac = account('123', 100) myac.deposit(800) myac.withdraw(500) fd = open( archive , w ) pickle.dump( myac, fd) fd.close() myac.deposit(200) print myac.balance fd = open( archive , r ) myac = pickle.load( fd ) fd.close() print myac.balance 500 300 500 500 600 400 600 600 300 500 Q31: import math print math.floor(5.5) 5 5.0 5.5 6 6.0 Q32: class Person: def __init__(self, id): self.id = id obama = Person(100) obama.__dict__['age'] = 49 print obama.age + len(obama.__dict__) 1 2 49 50 51 Q33: x = foo y = 2 print x + y foo foo foo foo 2 2 An exception is thrown Q34: def simpleFunction(): This is a cool simple function that returns 1 return 1 print simpleFunction.__doc__[10:14] simpleFunction simple func funtion cool Q35: sys.path.append('/root/mods') 改变python的启动路径 改变python目前的工作路径 添加一个新的python模块的搜索路径 从mods中移除所有的文件夹 Q36: import re sum = 0 pattern = 'back' if re.match(pattern, 'backup.txt'): sum += 1 if re.match(pattern, 'text.back'): sum += 2 if re.search(pattern, 'backup.txt'): sum += 4 if re.search(pattern, 'text.back'): sum += 8 print sum 3 7 13 14 15 Q37: names = ['Ramesh', 'Rajesh', 'Roger', 'Ivan', 'Nico'] 下面哪个语句能够让列表中的名字按行输出? print n .join(names) print names.join( n ) print names.concatenate( n ) print names.append( n ) print names.join( %sn , names) Q38: foo = {} print type(foo) set dict list tuple object Q39: country_counter = {} def addone(country): if country in country_counter: country_counter[country] += 1 else: country_counter[country] = 1 addone('China') addone('Japan') addone('china') print len(country_counter) 0 1 2 3 4 Q40: confusion = {} confusion[1] = 1 confusion['1'] = 2 confusion[1] += 1 sum = 0 for k in confusion: sum += confusion[k] print sum 1 2 3 4 5 Q41: confusion = {} confusion[1] = 1 confusion['1'] = 2 confusion[1.0] = 4 sum = 0 for k in confusion: sum += confusion[k] print sum 2 4 6 7 An exception is thrown Q42: bo ...

阅读全文 »

python quiz 1-24

Q1: def F(b, c): pass 1. 定义一个列表并且初始化 2. 定义一个函数,这个函数什么都不做 3. 定义一个函数,其参数传递通过 4. 定义一个空类 Q2: print type (1/2) 1. type int 2. type number 3. type float 4. type double 5. type tuple Q3: print type (1.0/2) 1. type int 2. type number 3. type float 4. type double 5. type tuple Q4: print type ([1,2]) 1. type tuple 2. type int 3. type set 4. type complex 5. type list Q5: def f():pass print type(f()) 1. type tuple 2. type function 3. type NoneType 4. type str 5. type type Q6: def f():pass print type(f) 1. type tuple 2. type function 3. type NoneType 4. type str 5. type type Q7: print type(2+3J) 1. type tuple 2. type complex 3. type unicode 4. type str 5. type dict Q8: print type(lambda:None) 1. type NoneType 2. type tuple 3. type type 4. type function 5. type bool Q9: print len([1,2,3,None,(),[],]) 1. Syntax error 2. 4 3. 5 4. 6 5. 7 Q10: d = lambda p: p * 2 t = lambda p: p * 3 x = 2 x = d(x) x = t(x) x = d(x) print x 1. 48 2. 7 3. 12 4. 24 5. 36 Q11: x=4.5 y=2 print x//y 1. 2.0 2. 2.25 3. 9.0 4. 20.25 5. 21 Q12: print len(set([1,1,2,3,3,3,3,4,5,5])) 1. 3 2. 5 3. 7 4. 10 5. 12 Q13: x=True y=False z=False if x or y and z: print yes else: print no 1. yes 2. no 3. fails to compile Q14: x = True y = False z = False if not x or y: print 1 elif not x or not y and z: print 2 elif not x or y or not y and x: print 3 else: print 4 1. 1 2. 2 3. 3 4. 4 5. 5 Q15: daysOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] print DAYS: %s, MONTHS %s % (daysOfWeek, months) 上述的代码能否成功输出星期一到星期天以及一月到十二月吗? 1. True 2. False Q16: f = None for i in range (5): with open( data.txt , w ) as f: if i 2: break print f.closed 1. True 2. False 3. None Q17: counter = 1 def doLotsOfStuff(): global counter for i in (1, 2, 3): counter += 1 doLotsOfStuff() print counter True 1. 1 2. 3 3. 4 4. 7 5. None of the above Q18: print r nwoow 1. new line then the string: woow 2. the text exactly like this: r nwoow 3. the text like exactly like t ...

阅读全文 »

python 菜谱(cookbook) 1.1

1.问题:

每次处理一个字符的方式处理字符串

2.分析:

 

python里面没有特别针对所谓“字符”的类型,但是在python字符就是长度为1的字符串,对于解决这个问题可以从下面几个角度入手:

  • 循环遍历一个字符串,依次访问字符串中的每个字符:(yourstring代表字符串,do()表示处理函数,,下面类似)
  1.  for c in yourstring:
  2.         do(c)
  • 可以利用map来处理字符串:
  • result=map(do,yourstring)
  • 可以利用列表解析:
  1. result=[do(cfor c in yourstring]
  • 可以直接调用list:
  1. list(yourstring)

 

阅读全文 »

Centos上安装nginx+PHP-FPM+Mysql+eAccelerator+memcache(LNMP)

对于LNMP的安装,我们可以选择两种方式:(1)LNMP的一键安装;(2)单独的包安装 一、LNMP一键安装 LNMP代表的就是Linux下Nginx、MySQL、PHP这种网站服务器架构,LAMP代表Linux下Apache、MySQL、PHP这种网站服务器架构,LNMP和LAMP的差别在于服务器Nginx和Apache,下面来看看nginx的优点: 作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率。 作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。 作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。 Nginx 安装非常的简单,配置文件 非常简洁(还能够支持perl语法),Bugs非常少的服务器: Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够在 不间断服务的情况下进行软件版本的升级 一键安装过程: 系统需求: 需要2 GB硬盘剩余空间 128M以上内存,OpenVZ的建议192MB以上 安装前建议先运行screen 安装步骤: 1、下载LNMP一键安装包: 可以选择使用下载版(推荐国外或者美国VPS使用)或者完整版(推荐国内VPS使用),如果使用下载版执行命令 wget -c http://soft.vpser.net/lnmp/lnmp0.7.tar.gz ,如果使用完整版,执行命令 wget -c http://soft.vpser.net/lnmp/lnmp0.7-full.tar.gz ,执行上述命令后LNMP一键安装包就会被下载到VPS上。 2、解压一键安装包: 执行tar zxvf lnmp0.7.tar.gz 或者tar zxvf lnmp0.7-full.tar.gz 就会将LNMP一键安装包解压缩。 3、CentOS下安装步骤 下载版执行命令 cd lnmp0.7/ ,完整版执行命令:cd lnmp0.7-full/ 然后再执行./centos.sh 也可以执行./centos.sh | tee lnmp.log (推荐这种方式,出错时可以到 论坛 上传lnmp.log日志),输入要绑定的域名(建议使用一个二级域名,该域名会绑定到/home/wwwroot/),回车,再输入要设置的MySQL root的密码,回车,提示 Press any key to start... ,按任意键开始安装。程序会自动安装编译Nginx、PHP、MySQL、phpMyAdmin、Zend这几个软件。 4、Debian下安装步骤 下载版执行命令 cd lnmp0.7/ ,完整版执行命令:cd lnmp0.7-full/ 然后执行./debian.sh 也可以执行./debian.sh | tee lnmp.log (推荐这种方式,出错时可以到 论坛 上传lnmp.log日志),输入要绑定的域名(建议使用一个二级域名,该域名会绑定到/home/wwwroot/),回车,再次输入VPS/服务器所在位置:asia、america、europe、oceania或africa,回车,再输入要设置的MySQL root的密码,回车,提示 Press any key to start... ,按任意键开始安装。程序会自动安装编译Nginx、PHP、MySQL、phpMyAdmin、Zend这几个软件。 5、Ubuntu下安装步骤 下载版执行命令 cd lnmp0.7/ ,完整版执行命令:cd lnmp0.7-full/ 然后执行./ubuntu.sh 也可以执行./ubuntu.sh | tee lnmp.log (推荐这种方式,出错时可以到 论坛 上传lnmp.log日志),输入要绑定的域名(建议使用一个二级域名,该域名会绑定到/home/wwwroot/),回车,再输入要设置的MySQL root的密码,回车,提示 Press any key to start... ,按任意键开始安装。程序会自动安装编译Nginx、PHP、MySQL、phpMyAdmin、Zend这几个软件。 安装其他组件 1、安装eAccelerator,执行如下命令:./eaccelerator.sh 就会自动安装并重启web服务。 2、安装ionCube,执行如下命令:./ionCube.sh 就会自动安装并重启web服务。 3、安装PureFTPd和管理面板,执行如下命令:./pureftpd.sh 按提示输入你MySQL的root密码、FTP用户管理面板的密码、MySQl的FTP数据库密码(可直接回车,自动生成一个密码),回车确认,就会自动安装PureFTPd,安装完PureFTPd,在浏览器执行http://你的域名或IP/ftp/ 输入你前面设置的FTP用户管理面板的密码,就可以管理。 4、安装VsFTPD,执行如下命令:./vsftpd.sh 就会自动安装上vsftpd,只需要执行命令:useradd -d /home/wwwroot -s /sbin/nologin adminftp 添加上帐号指定好ftp帐号的根目录,再执行:passwd adminftp 设置上密码,登录就可以了。 5、安装memcache,先安装libevent,安装memcached,同时需要安装中指定libevent的安装位置,安装PHP的memcache扩展 虚拟主机管理 1、添加虚拟主机,执行如下命令:/root/vhost.sh 根据提示输入要绑定的域名,回车,如果需要添加更多的域名,输入y,再输入要另外绑定的域名,多个域名可以用空格隔开。再输入域名绑定的目录(绝对目录,如/home/wwwroot/lnmp,如果不填默认是/home/wwwroot/绑定的域名),再选择是否添加伪静态规则,默认已经有了Discuz、Wordpress、Sablog、emlog、dabr,可直接输入以上名称即可,如果需要添加自定义伪静态规则,直接输入一个想要的名字,程序会自动创建伪静态文件,直接在/usr/local/nginx/conf/你自定义的伪静态名字.conf 里面添加伪静态规则就行。接下来会提示是否需要启用日志功能,一般情况下不需要启动,直接输入n就行,如需启动,输入y,再输入要定义的日志文件名字,回车就会自动添加虚拟主机。 2、删除虚拟主机,ssh执行:rm /usr/local/nginx/conf/vhost/域名.conf 状态管理 LNMP状态管理: /root/lnmp {start|stop|reload|restart|kill|status} Nginx状态管理:/etc/init.d/nginx {start|stop|reload|restart} PHP-FPM状态管理:/etc/init. ...

阅读全文 »

Beautiful Soup 中文文档之五

搜索剖析树 Beautiful Soup提供了许多方法用于浏览一个剖析树,收集你指定的 Tag 和 NavigableString 。 有几种方法去定义用于Beautiful Soup的匹配项。我们先用深入解释最基本的一种搜索方法 findAll 。和前面一样,我们使用下面这个文档说明: from BeautifulSoup import BeautifulSoup doc = [' html head title Page title /title /head ', ' body p id="firstpara" align="center" This is paragraph b one /b .', ' p id="secondpara" align="blah" This is paragraph b two /b .', ' /html '] soup = BeautifulSoup(''.join(doc)) print soup.prettify() # html # head # title # Page title # /title # /head # body # p id="firstpara" align="center" # This is paragraph # b # one # /b # . # /p # p id="secondpara" align="blah" # This is paragraph # b # two # /b # . # /p # /body # /html 还有, 这里的两个方法( findAll 和 find )仅对 Tag 对象以及顶层剖析对象有效,但 NavigableString 不可用。这两个方法在 Searching 剖析树内部 同样可用。 The basic find method: findAll( name , attrs , recursive , text , limit , **kwargs ) 方法 findAll 从给定的点开始遍历整个树,并找到满足给定条件所有 Tag 以及 NavigableString 。 findall 函数原型定义如下: findAll(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs) 这些 参数会反复的在这个文档中出现。其中最重要的是 name 参数和keywords参数(译注:就是**kwargs参数)。 参数 name 匹配tags的名字,获得相应的结果集。有几种方法去匹配name,在这个文档中会一再的用到。 最简单用法是仅仅给定一个tag name值。下面的代码寻找文档中所有的 B Tag : soup.findAll('b') # [ b one /b , b two /b ] 你可以传一个正则表达式。下面的代码寻找所有以b开头的标签: import re tagsStartingWithB = soup.findAll(re.compile('^b')) [tag.name for tag in tagsStartingWithB] # [u'body', u'b', u'b'] 你可以传一个list或dictionary。下面两个调用是查找所有的 TITLE 和 P 标签。他们获得结果一样,但是后一种方法更快一些: soup.findAll(['title', 'p']) # [ title Page title /title , # p id="firstpara" align="center" This is paragraph b one /b . /p , # p id="secondpara" align="blah" This is paragraph b two /b . /p ] soup.findAll({'title' : True, 'p' : True}) # [ title Page title /title , # p id="firstpara" align="center" This is paragraph b one /b . /p , # p id="secondpara" align="blah" This is paragraph b two /b . /p ] 你可以传一个 True 值,这样可以匹配每个tag的name:也就是匹配每个tag。 allTags = soup.findAll(True) [tag.name for tag in allTags] [u'html', u'head', u'title', u'body', u'p', u'b', u'p', u'b'] 这看起来不是很有用,但是当你限定属性(attribute)值时候,使用 True 就很有用了。 你可以传 callable对象,就是一个使用 Tag 对象作为它唯一的参数,并返回布尔值的对象。 findAll 使用的每个作为参数的 Tag 对象都会传递给这个 callable对象,并且如果调用返回 True ,则这个tag便是匹配的。 下面是查找两个并仅两个属性的标签(tags): soup.findAll(lambda tag: len(tag.attrs) == 2) # [ p id="firstpara" align="center" This is paragraph b one /b . /p , # p id="secondpara" align="blah" This is paragraph b two /b . /p ] 下面是寻找单个字符为标签名并且没有属性的标签: soup.findAll(lambda tag: len(tag.name) == 1 and not tag.attrs) # [ b one /b , b two /b ] keyword参数用于筛选tag的属性。下面这个例子是查找拥有属性align且值为center的所有标签: soup.findAll(align="center") # [ p id="firstpara" align="center" This is paragraph b one /b . /p ] 如同 name 参数,你也可以使用不同的keyword参数对象,从而更加灵活的指定属性值的匹配条件。你可以向上面那样传递一个字符串,来匹配属性的值。你也可以传递一个正则表达式,一个列表(list),一个哈希表(hash),特殊值 True 或 None ,或者一个可调用的以属性值为参数的对象(注意:这个值可能为 None )。 一些例子: soup . findAll ( id = re . compile ( "para$" )) #[ p id="firstpara" align="center" This is paragraph b one /b . /p ,# p id="secondpara" align="blah" This is paragraph b two /b . /p ...

阅读全文 »

Beautiful Soup 中文文档之四

Navigating剖析树 Tag 对象都有如下含有所有的成员的列表(尽管,某些实际的成员值可能为 None ). NavigableString 对象也有下面这些成员,除了 contents 和 string 成员。 parent 上面那个 例子 中, HEAD Tag 的parent是 HTML Tag . HTML Tag 的parent是 BeautifulSoup 剖析对象自己。 剖析对象的parent是 None . 利用 parent ,你可以向前遍历剖析树。 soup.head.parent.name # u'html' soup.head.parent.parent.__class__.__name__ # 'BeautifulSoup' soup.parent == None # True contents 使用 parent 向前遍历树。使用 contents 向后遍历树。 contents 是 Tag 的有序列表, NavigableString 对象包含在一个页面元素内。只有最高层的剖析对象和 Tag 对象有 contents 。 NavigableString 只有strings,不能包含子元素,因此他们也没有 contents . 在上面的 例子 中, contents 的第一个 P Tag 是个列表,包含一个 NavigableString ("This is paragraph "), 一个 B Tag , 和其它的 NavigableString (".")。而 contents 的 B Tag : 包含一个 NavigableString ("one")的列表。 pTag = soup.p pTag.contents # [u'This is paragraph ', b one /b , u'.'] pTag.contents[1].contents # [u'one'] pTag.contents[0].contents # AttributeError: 'NavigableString' object has no attribute 'contents' string 为了方便,如果一个标签只有一个子节点且是字符串类型,这个自己可以这样访问 tag.string ,等同于 tag.contents[0] 的形式。 在上面的 例子 中, soup.b.string 是个 NavigableString 对象,它的值是Unicode字符串"one". 这是剖析树中 B Tag 的第一个string。 soup.b.string # u'one' soup.b.contents[0] # u'one' 但是 soup.p.string 是 None , 剖析中的第一个 P Tag 拥有多个子元素。 soup.head.string 也为 None , 虽然 HEAD Tag只有一个子节点,但是这个子节点是 Tag 类型 ( TITLE Tag ),不是 NavigableString 。 soup.p.string == None # True soup.head.string == None # True nextSibling 和 previousSibling 使用它们你可以跳往在剖析树中同等层次的下一个元素。在上面的 文档中 , HEAD Tag 的 nextSibling 是 BODY Tag ,因为 BODY Tag 是在 html Tag 的下一层。 BODY 标签的 nextSibling 为 None , 因为 HTML 下一层没有标签是直接的在它之后。 soup.head.nextSibling.name # u'body' soup.html.nextSibling == None # True 相应的 BODY Tag 的 previousSibling 是 HEAD 标签, HEAD Tag 的 previousSibling 为 None : soup.body.previousSibling.name # u'head' soup.head.previousSibling == None # True 更多例子: P Tag 的第一个 nextSibling 是第二个 P Tag 。第二个 P Tag 里的 B Tag 的 previousSibling 是 NavigableString "This is paragraph"。 这个 NavigableString 的 previousSibling 是 None , 不会是第一个 P Tag 里面的任何元素。 soup.p.nextSibling # p id="secondpara" align="blah" This is paragraph b two /b . /p secondBTag = soup.findAlll('b')[1] secondBTag.previousSibling # u'This is paragraph' secondBTag.previousSibling.previousSibling == None # True next 和 previous 使用它们可以按照soup处理文档的次序遍历整个文档,而不是它们在剖析树中看到那种次序。例如 HEAD Tag 的 next 是 TITLE Tag , 而不是 BODY Tag 。这是因为在 原始文档 中, TITLE tag 直接在 HEAD 标签之后。 soup.head.next # u'title' soup.head.nextSibling.name # u'body' soup.head.previous.name # u'html' Where next and previous are concerned, a Tag 's contents come before its nextSibling . 通常不会用到这些成员,但有时使用它们能够非常方便地从剖析树获得不易找到的信息。 遍历一个标签(Iterating over a Tag) 你可以像遍历list一样遍历一个标签( Tag )的 contents 。这非常有用。类似的,一个Tag的有多少child可以直接使用len(tag)而不必使用len(tag.contents)来获得。以上面那个 文档 中的为例: for i in soup.body: print i # p id="firstpara" align="center" This is paragraph b one /b . /p # p id="secondpara" align="blah" This is paragraph b two /b . /p len(soup.body) # 2 len(soup.body.contents) # 2 使用标签(tag)名作为成员 像剖析对象或Tag对象的成员一样使用Tag名可以很方便的操作剖析树。前面一些例子我们已经用到了这种方式。以上述 文档 为例, soup.head 获得文档第一个 HEA ...

阅读全文 »

Beautiful Soup 中文文档之三

输出文档 你可以使用 str 函数将Beautiful Soup文档(或者它的子集)转换为字符串,或者使用它的code prettify或 renderContents 。你也可以使用 unicode 函数以Unicode字符串的形式获得。 prettify 方法添加了一些换行和空格以便让文档结构看起来更清晰。它也将那些只包含空白符的,可能影响一个XML文档意义的文档节点(nodes)剔除(strips out)。 str 和 unicode 函数不会剔除这些节点,他们也不会添加任何空白符。 看看这个例子: from BeautifulSoup import BeautifulSoup doc = " html h1 Heading /h1 p Text" soup = BeautifulSoup(doc) str(soup) # ' html h1 Heading /h1 p Text /p /html ' soup.renderContents() # ' html h1 Heading /h1 p Text /p /html ' soup.__str__() # ' html h1 Heading /h1 p Text /p /html ' unicode(soup) # u' html h1 Heading /h1 p Text /p /html ' soup.prettify() # ' html n h1 n Headingn /h1 n p n Textn /p n /html ' print soup.prettify() # html # h1 # Heading # /h1 # p # Text # /p # /html 可以看到使用文档中的tag成员时 str 和 renderContents 返回的结果是不同的。 heading = soup.h1 str(heading) # ' h1 Heading /h1 ' heading.renderContents() # 'Heading' 当你调用 __str__ , prettify 或者 renderContents 时,你可以指定输出的编码。默认的编码( str 使用的)是UTF-8。下面是处理ISO-8851-1的串并以不同的编码输出同样的串的例子。 from BeautifulSoup import BeautifulSoup doc = "Sacrxe9 bleu!" soup = BeautifulSoup(doc) str(soup) # 'Sacrxc3xa9 bleu!' # UTF-8 soup.__str__("ISO-8859-1") # 'Sacrxe9 bleu!' soup.__str__("UTF-16") # 'xffxfeSx00ax00cx00rx00xe9x00 x00bx00lx00ex00ux00!x00' soup.__str__("EUC-JP") # 'Sacrx8fxabxb1 bleu!' 如果原始文档含有编码声明,Beautiful Soup会将原始的编码声明改为新的编码。也就是说,你载入一个HTML文档到 BeautifulSoup 后,在输出它,不仅HTML被清理过了,而且可以明显的看到它已经被转换为UTF-8。 这是HTML的例子: from BeautifulSoup import BeautifulSoup doc = """ html meta http-equiv="Content-type" content="text/html; charset=ISO-Latin-1" Sacrxe9 bleu! /html """ print BeautifulSoup(doc).prettify() # html # meta http-equiv="Content-type" content="text/html; charset=utf-8" / # Sacré bleu! # /html 这是XML的例子: from BeautifulSoup import BeautifulStoneSoup doc = """ ?xml version="1.0" encoding="ISO-Latin-1" Sacrxe9 bleu!""" print BeautifulStoneSoup(doc).prettify() # ?xml version='1.0' encoding='utf-8' # Sacré bleu! 剖析树 到目前为止,我们只是载入文档,然后再输出它。现在看看更让我们感兴趣的剖析树: Beautiful Soup剖析一个文档后生成的数据结构。 剖析对象 ( BeautifulSoup 或 BeautifulStoneSoup 的实例)是深层嵌套(deeply-nested), 精心构思的(well-connected)的数据结构,可以与XML和HTML结构相互协调。剖析对象包括2个其他类型的对象, Tag 对象,用于操纵像 TITLE , B 这样的标签; NavigableString 对象,用于操纵字符串,如"Page title"和"This is paragraph"。 NavigableString 的一些子类 ( CData , Comment , Declaration , and ProcessingInstruction ), 也处理特殊XML结构。 它们就像 NavigableString 一样, 除了但他们被输出时,他们会被添加一些额外的数据。下面是一个包含有注释(comment)的文档: from BeautifulSoup import BeautifulSoup import re hello = "Hello! !--I've got to be nice to get what I want.-- " commentSoup = BeautifulSoup(hello) comment = commentSoup.find(text=re.compile("nice")) comment.__class__ # class 'BeautifulSoup.Comment' comment # u"I've got to be nice to get what I want." comment.previousSibling # u'Hello! ' str(comment) # " !--I've got to be nice to get what I want.-- " print commentSoup # Hello! !--I've got to be nice to get what I want.-- 现在,我们深入 研究一下我们开头使用的那个文档: from BeautifulSoup import BeautifulSoup doc = [' html head title Page title /title /head ', ' body p id="firstpara" align ...

阅读全文 »