码迷,mamicode.com
首页 > 编程语言 > 详细

Python html.parser库学习小结

时间:2015-06-08 23:11:46      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:

分类路径:/Datazen/DataMining/Crawler/
 
前段时间,一朋友让我做个小脚本,抓一下某C2C商城上竞争对手的销售/价格数据,好让他可以实时调整自己的营销策略。自己之前也有过写爬虫抓某宝数据的经历,实现的问题不大,于是就答应了。初步想法是利用pyhton中的urllib.request和re两个lib(本文示例用的是Pyhton 3.4 ,2.x的请自行切换),外加上其他的统计分析功能的话,最多两个晚上(白天要工作)可以搞定。实际上做的过程中,遇到了两个主要困难:
(1)电商网站对于交易数据的保护很好。小爬虫动不动就会被ban掉或者采用一些其他的保护措施使得其无法正常采集所需的数据,需要添加额外的代码处理各种虐心的情况;
(2)正则表达式实在是难写,而且很复杂和很难维护。于是自己也思考有没有其他的解决方案——本文就是对其中一解决方案的初步介绍。
 
一开始想到的当然是著名的第三方库Beautifulsoup(作为一个广东男人,我习惯把它称为”靓汤“)。这个库很强大,但正因为它强大,需要一点学习时间而我需要快点上手,于是只好日后再学(到时再写一篇Beautifulsoup学习总结)。权衡以后,最后目光转向了Python Standard Library中的html.parser。
 
html.parser是一个非常简单和实用的库,它的核心是HTMLParser类。从源码来看,它内部封装了一系列regular expression。工作的流程是:当你feed给它一个类似HTML格式的字符串时,它会调用goahead方法向前迭代各个标签,并调用对应的parse_xxxx方法提取start_tag, tag, attrs data comment和end_tag等等标签信息和数据,然后调用对应的方法对这些抽取出来的内容进行处理。整个HTMLParser的大致结构如下图所示:
 
技术分享
 
 
可以发现,处理开始标签(handle_starttag)、结束标签(handle_endtag)和处理数据(handle_data)等处理函数在HTMLParser里是没有实现的(pass),这需要我们继承HTMLParser这个类的并覆盖这些方法。详细可以参阅python文档,这里重点介绍几个常用的方法:
 
  1. feed(data):主要用于接受带html标签的str,当调用这个方法时并提供相应的data时,整个实例(instance)开始执行,结束执行close()。
  2. handle_starttag(tag, attrs): 这个方法接收Parse_starttag返回的tag和attrs,并进行处理,处理方式通常由使用者进行覆盖,本身为空。例如,连接的start tag是<a>,那么对应的参数tag=’a’(小写)。attrs是start tag <>中的属性,以元组形式(name, value)返回(所有这些内容都是小写)。例如,对于<A HREF="http://www.baidu.com“>,那么内部调用形式为:handle_starttag(’a’,[(‘href’,’http://www.baidu.com)]).
  3. handle_endtag(tag):跟上述一样,只是处理的是结束标签,也就是以</开头的标签。
  4. handle_data(data):处理的是网页的数据,也就是开始标签和结束标签之间的内容。例如:<script>...</script>的省略号内容
  5. reset():将实例重置,包括作为参数输入的数据进行清空。
 
举个例子吧。例如我们有以下一堆带HTML标签的数据,

     【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机
   </h3>
   <p class="tb-subtitle">
 【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】    【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】    【金冠信誉+顺丰包邮+全国联保---多重保障】
 </p>
   <div id="J_TEditItem" class="tb-editor-menu"></div>
 </div>
<h3 class="tb-main-title" data-title="【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡">
     【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡
   </h3>
   <p class="tb-subtitle">
 [红米手机2代颜色版本较多,请亲们阅读购买说明按需选购---感谢光临] 【金皇冠信誉小米手机集市销量第一】【购买套餐送高清钢化膜+线控通话耳机+ 剪卡器(含还原卡托)+ 防辐射贴+专用高清贴膜+ 擦机布+ 耳机绕线器+手机电影支架+ 一年延保服务+ 默认享受顺丰包邮 !
 </p>
   <div id="J_TEditItem" class="tb-editor-menu"></div>
 </div>

很明显,这里面包含了两台手机,我们的目标是提取两个手机的名字出来。
 
由于当我们feed这个html到HTMLParser中后,他们所有的标签都迭代,如果需要它只提取我们需要的数据时,我们需要设置当handle_starttag遇到那个标签和属性时,才调用handle_data并print出我们的结果,这个时候我们可以使用一个flg作为判定,代码如下:
 
#定义一个MyParser继承自HTMLParser
class MyParser(HTMLParser):
    re=[]#放置结果
    flg=0#标志,用以标记是否找到我们需要的标签
    def handle_starttag(self, tag, attrs):
        if tag==‘h3‘:#目标标签
            for attr in attrs:
                if attr[0]==‘class‘ and attr[1]==‘tb-main-title‘:#目标标签具有的属性
                    self.flg=1#符合条件则将标志设置为1
                    break
        else:
            pass
 
    def handle_data(self, data):
        if self.flg==1:
            self.re.append(data.strip())#如果标志为我们需要的标志,则将数据添加到列表中
            self.flg=0#重置标志,进行下次迭代
        else:
            pass


my=MyParser()
my.feed(html)
 
运行结果如下,达到了我们的预期:

技术分享

 
上面只是HTMLParser一个非常简单的应用,但却可以反应了HTMLParser这个类的一些特质。有了这些基本的认识后,我们就可以将相关功能进行扩展,从而形成一个标准的爬虫了。下次,我们将利用相关的知识,构建一个基本的网络爬虫,敬请期待哦。
 
--------------------------------------------------
本文为作者原创文章,转摘请注明出处:@Datazen

Python html.parser库学习小结

标签:

原文地址:http://www.cnblogs.com/zhanghaohong/p/4562127.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!