python程序员的进化(The Evolution of a Python Programmer )

不久前,在互联网上出现了一篇有趣的文章,讲的是对于同一个问题,不同层次的程序员编出的Python代码显示出了不同的风格,代码都很简单,有趣。这篇文章的原始出处在 这里 ,我把它整理了一下,并修改了几处错误。 编程新手 1 2 3 4 5 6 def factorial ( x ) : if x == 0 : return 1 else : return x * factorial ( x - 1 ) print factorial ( 6 ) 一年编程经验(学Pascal的) 1 2 3 4 5 6 7 8 def factorial ( x ) : result = 1 i = 2 while i = x: result = result * i i = i + 1 return result print factorial ( 6 ) 一年编程经验(学C的) 1 2 3 4 5 6 7 8 9 def fact ( x ) : #{ result = i = 1 ; while ( i = x ) : #{ result * = i ; i += 1 ; #} return result ; #} print ( fact ( 6 ) ) 一年编程经验(读过 SICP ) 1 2 3 4 5 @tailcall def fact ( x, acc= 1 ) : if ( x 1 ) : return ( fact ( ( x - 1 ) , ( acc * x ) ) ) else : return acc print ( fact ( 6 ) ) 一年编程经验(Python) 1 2 3 4 5 6 def Factorial ( x ) : res = 1 for i in xrange ( 2 , x + 1 ) : res * = i return res print Factorial ( 6 ) 懒惰的Python程序员 1 2 3 def fact ( x ) : return x 1 and x * fact ( x - 1 ) or 1 print fact ( 6 ) 更懒的Python程序员 1 2 f = lambda x: x and x * f ( x - 1 ) or 1 print f ( 6 ) Python 专家 1 2 fact = lambda x: reduce ( int . __mul__ , xrange ( 2 , x + 1 ) , 1 ) print fact ( 6 ) Python 黑客 1 2 3 4 5 6 import sys @tailcall def fact ( x, acc= 1 ) : if x: return fact ( x. __sub__ ( 1 ) , acc. __mul__ ( x ) ) return acc sys . stdout . write ( str ( fact ( 6 ) ) + ' n ' ) 专家级程序员 1 2 from c_math import fact print fact ( 6 ) 大英帝国程序员 1 2 from c_maths import fact print fact ( 6 ) Web 设计人员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def factorial ( x ) : #------------------------------------------------- #--- Code snippet from The Math Vault --- #--- Calculate factorial (C) Arthur Smith 1999 --- #------------------------------------------------- result = str ( 1 ) i = 1 #Thanks Adam while i = x: #result = result * i #It's faster to use *= #result = str(result * result + i) #result = int(result *= i) #?????? result = str ( int ( result ) * i ) #result = int(str(result) * i) i = i + 1 return result print factorial ( 6 ) Unix 程序员 1 2 3 4 import os def fact ( x ) : os . system ( 'factorial ' + str ( x ) ) fact ( 6 ) Windows 程序员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 NULL = None def CalculateAndPrintFactorialEx ( dwNumber, hOutputDevice, lpLparam, lpWparam, lpsscSecurity, * dwReserved ) : if lpsscSecurity ! = NULL: return NULL #Not implemented dwResult = dwCounter = 1 while dwCounter = dwNumber: dwResult * = dwCounter dwCounter += 1 hOutputDevice. write ( str ( dwResult ) ) hOutputDevice. write ( ' n ' ) return 1 import sys CalculateAndPrintFactorialEx ( 6 , sys . stdout , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) 企业级程序员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 def new ( cls, * args, ** kwargs ) : return cls ( * args, ** kwargs ) class Number ( object ) : pass class IntegralNumber ( int , Number ) : def toInt ( self ) : return new ( int , self ) class InternalBase ( object ) : def __init__ ( self , base ) : self . base = base. toInt ( ) def getBase ( self ) : return n ...

阅读全文 »

python提升运行速度一例

尝试了一下用Python实现的K-Means Clustering算法,抽样了10000篇百科词条,分为1000个类,分词后词语总数为130000左右。如果把1000个类定义为1000个向量,每个向量的元素个数为130000,K-Means Clustering算法的第一步是初始化这1000个向量的值,如果每个向量元素的值用float型存储,则需要的内存为: 1000 * 130000 * sizeof(float) 约 520M 左右。 最初用Python的list存储,动态扩展列表大小,结果内存用到近3G还没初始化完成,只好赶紧kill掉了。 改用 NumPy 存成固定数组的类别,发现内存使用量和计算结果基本一致,而且NumPy支持数组的数学计算,确实方便了不少,但即便如此,性能仍不够理想,K-Means算法第一次迭代花了一个小时还没完成。 怀疑K-Means算法的pearson距离计算时间较长(没有用profile工具论证过),用 Cython 重新改写了该算法,并尽可能缓存计算中间结果。第一轮迭代耗时1个多小时,算是有了进步。 由于K-Means算法费CPU较多,改写了计算逻辑,用multiprocessing模块并行计算,在4核的CPU上速度提升了4倍,第一轮迭代花了约30分钟。但multiprocessing需要fork多个进程,每个进程的内存使用量均在600M上下想,4个进程占用了2.4G内存,代价有些大。而且计算结果在不同的进程间传递,性能开销也是存在的。 multiprocessing + 共享内存可以解决这个问题,但Python的数据结构不好表示。 继而想到写C的动态链接库,用Python的ctypes模块调用该动态链接库完成计算过程,C的动态链接库则创建系统线程,这样能有效躲过Python的GIL。问题是C代码有时候确实需要访问Python的数据对象,这只能通过Python的C扩展模块实现了,但C的扩展模块能访问ctypes的原始C指针吗?如果只能通过Python的C API访问,则GIL是绕不开的,我们的目标是尽可能少地锁住Python虚拟机。 解决办法是修改Python的ctypes源码,让它导出函数 addressof 的C API,这样在其他的C扩展模块里就能拿到ctypes的原始数据块指针。addressof的返回结果是一个long的PyObject包装对象,通过 PyLong_AsVoidPtr调用即可获取其值。 因此最后的解决办法是下载Python的源码,修改模块_ctypes的源码,通过Capsule导出C API。继而编写Python的C扩展模块,创建线程池,直接操作ctypes定义的数据内存。由于Python数据结构是非线程安全的,访问它们仍需获得GIL,但用到的可能性很小。程序的主体逻辑仍由Python代码构造,包括必要的ctypes数据结构。 代码改写后一次K-Means迭代不到一分钟就完成了,4颗CPU全跑满,内存仅占用600M左右,跟预期完全一致。 总结 Python大多数时间能如我们预期那样工作 涉及到数值计算和海量循环,Python表现极其糟糕 Cython + NumPy 可解决部分计算问题和内存问题,但GIL无法避免 multiprocessing能解决SMP/GIL问题,但内存问题解决不了,也许共享内存+ctypes是个办法,没尝试过 ctypes + C的动态链接库创建系统线程能解决GIL和内存共享问题,但无法在C中操作Python对象 ctypes + Python C扩展意义不大,因为C扩展无法直接操作ctypes的数据指针 改写后的ctypes + Python C扩展解决了性能和内存消耗问题 ctypes数据类型能被msgpack之类的工具快速序列化到磁盘,但恢复的时候只能恢复成list类型,这可能是美中不足的地方。 ...

阅读全文 »

python 自动化测试模块介绍

 

Win32 GUI自动化测试模块:

1. pywinauto:

    下载链接:http://sourceforge.net/projects/pywinauto/

    在线文档:http://pywinauto.googlecode.com/hg/pywinauto/docs/contents.html

    邮件列表:https://lists.sourceforge.net/lists/listinfo/pywinauto-users

    其它相关链接: http://code.google.com/p/pywinauto/

2. Watsup: http://www.tizmoi.net/watsup/intro.html

3. winGuiAuto: http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html

Web 自动化测试模块

1. twill: 项目主页:http://twill.idyll.org/

2. PAMIE: 项目主页: http://pamie.sourceforge.net/

远程操作、命令行控制类的自动化测试:

1. 项目主页:http://www.noah.org/wiki/Pexpect

2. 探索Pexpect,第 1 部分:剖析 Pexpect : http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect1/

3. 探索Pexpect,第 2 部分:Pexpect 的实例分析 : http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect2/

阅读全文 »

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)

 

阅读全文 »

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 ...

阅读全文 »