记得之前写过一篇文章,html2javaben,并发布了一个相关的组件,大概的功能就是把抓取的html页面后抽取其中的结构化数据进行二次加工。最近在用python也在写一个好玩的抓取网页的东西,也想封装一个python版的这样的组件用,想不到前后大概花了2个小时构思,2个小时编码就搞定了。想起了以前用java写这个东西时,总是免不了最后出来的东西让你特别有“成就感”,看这包名结构就知道了,呵呵。
现在就用python去实现这个功能,感受下这个愉快的过程.
我们还是以之前文章中的html代码做为示例:
"width: 100px;" align="left"> 姓名: | tony |
---|---|
"left"> 员工编号: | ite00395 |
"left"> 性别: | man |
"left"> Email: | [email protected] |
"left"> MSN: | [email protected] |
"left"> 公司电话: | 13712548548 |
"left"> 移动电话: | 1371489634 |
"left"> 所属部门: | "middle"> P后台项目组 |
"left"> 部门地址: | "middle"> |
现在我们需要抽取的数据是这样的格式:
{'Name':'tony', 'Work':'ite00395', 'Sex':'man', 'Email':'[email protected]', 'Msn':'[email protected]', 'Phone':'13712548548', 'Mobile':'Mobile', 'Department':'P后台项目组', 'DeptAddress':''}
我希望封装的解析组件能完成如下的代码:
html_regular = {'Name':r'(.+?)', 'Work':r'(.+?)', 'Sex':r'(.+?)', ........} HtmlParser(html_regular).parse(html)
上面两句代码的意思很明确:第一句代码是定义了html字符中我们待抽取的结构化数据的组织形式,即通过什么样的正则表达式去把这些数据匹配出来。第二句代码就是构造一个解析器去解析指定的html参数,输出我们想要的结构化数据.
对于比较复杂的数据结构,如List对象,嵌套对象,等等,我们也要提供支持。
list_regular = [{'groupKey':r'在html源码中分隔List数据的分隔符代码'}, {'description':r'匹配description的正则表达式', 'date':r'匹配date的正则表达式'}]
以上结构是抽取List重复数据时的表达式定义:List中必需有且只有两个元素,第一个'groupKey'是对当前List结构在Html源码中的分隔字符,第二个元素是List组成元素的正则表达式匹配描述。
还是以前面的Html源码举例,如果现在的Html中有多个这个的数据:
<table style="height: 306px; width: 99%;"> <tr> <th style="width: 100px;" align="left"> 姓名:th> <td> <span id="lblName">tony1span> td> tr> .... .... .... table> <table style="height: 306px; width: 99%;"> <tr> <th style="width: 100px;" align="left"> 姓名:th> <td> <span id="lblName">tony2span> td> tr> .... .... .... table> <table style="height: 306px; width: 99%;"> <tr> <th style="width: 100px;" align="left"> 姓名:th> <td> <span id="lblName">tony3span> td> tr> .... .... .... table>
可以看到这里的结构就是List,且有三个元素数据。所以这时的regular表达式应该这样描述:
list_regular = [{'groupKey':r''}, {'Name':r'(.+?)', ...}]
以上描述完了我们希望的这个组件所具有的功能后,我们再看下具体的实现代码:
1 # encoding: utf-8 2 3 import re 4 5 """ 6 Translate string of html to obj by specified regular 7 """ 8 9 class HtmlParser(): 10 def __init__(self,regular): 11 self.regular = regular 12 13 def parse(self,html): 14 return parseNode(self.regular,html) 15 16 17 def processReg(exp,html): 18 p = re.compile(exp,re.DOTALL) 19 m = p.search(html) 20 if m: 21 try: 22 return m.group(1).strip() 23 except IndexError: 24 pass 25 26 27 28 29 def parseNode(node,html): 30 if type(node) is list: 31 objList = [] 32 for itemStr in getSubHtmlGenerator(node[0]['groupKey'],html): 33 objList.append(parseNode(node[1],itemStr)) 34 return objList 35 else: 36 obj = {} 37 for name,regular in node.items(): 38 if type(regular) is str: 39 obj[name] = processReg(regular,html) 40 else: 41 obj[name] = parseNode(regular,html) 42 return obj 43 44 45 46 def getSubHtmlGenerator(groupKey,html): 47 while True: 48 start = html.find(groupKey) 49 if start != -1: 50 end = html[start+len(groupKey):].find(groupKey) 51 if end!= -1: 52 yield html[start:end + start + len(groupKey)] 53 html = html[end+start+len(groupKey):] 54 else: 55 yield html[start:] 56 break 57 else: 58 break可以看到,包括注释加空行,总共58行代码,如果大家遇到过这样的需求和看过上面所写的这些,应该知道这58行代码所做的事,是不是很简单?
总结:
我写这篇文章不是说想介绍我写的这个组件,因为它都称不上一个组件,只是写了一个类,提供了一个方法。我真正的想说的是python这个语言所强在的东西,数据结构即代码,所写的,即是所表达的意思,简单清晰。转载于:https://www.cnblogs.com/jcli/archive/2013/03/04/2942935.html