BeautifulSouphtml
bs是个html解析模块,经常使用来作爬虫?html5
■ 安装python
BeautifulSoup能够经过pip来安装,用pip install beautifulsoup4 便可。可是仅仅这样安装的bs,其默认的html解析器是python自带的HTMLParser模块,性能不是很好。能够考虑安装性能更加好的lxml和html5lib模块:pip install html5lib正则表达式
■ 基本用法函数
BeautifulSoup有官方文档,能够查阅性能
① 创建BeautifulSoup对象,它是基于一个html字符串或者一个文件spa
from bs4 import BeautifulSoup soup = BeautifulSoup("...一串html") #或者 soup = BeautifulSoup(open("文件路径","r")) print soup.prettify() #能够美化这段html并打印出来
② 四类对象code
bs将一个html抽象成一个树形结构,每一个节点都是一个python里的对象。共分红了四种对象。xml
● Tag类对象htm
即html中的标签,BeautifulSoup对象(以上面代码中的soup为例)能够直接在后面接上某种标签的名称,获得的对象是该种标签在这段html中的第一个实例。
好比对于print soup.h1 >>> <h1 class="...">...</h1> (bs里的html对象是可打印的,打印出来就是html原文)
每一个Tag类对象都有两个属性,name和attrs。
name就是标签的名字,而attrs是个字典,里面记录了全部这个tag的属性值。好比有tag是<h1 class="space-seo space-meta" name="testname">HELLO</h1>
其name就是u'h1',而attrs是{u'class':[u'space-seo',u'space-meta'],u'name':u'testname'} //注意区别tag对象的name属性和写在attrs里面的name属性的区别,另外全部被存到变量里的html内容所有都变成了unicode对象。在print的时候能够指定encode,默认encode是utf-8。还有,全部class属性都默认都被解析成一个列表,即使只有一个class值,也会成为[u'class_value']
固然,在定位到Tag对象以后能够获取查看其属性值,另外一方面,也能够对其属性值等进行修改,修改完了以后就是存在内存中的这个变量里面的,最终能够输出成文件的形式。
● String对象 //selenium用的是text来指代标签内部的文本内容,而bs用的是string。并且对于<div>这种自己不带文本带后辈节点可能带文本的标签二者意义不一样。selenium中的.text会带出来全部后辈节点中的文本,而bs中的这个.string返回的是None
String对象用于表明每一个元素所含的文字部分,在标签后面加上.string便可调用
print soup.h1.string >>> HELLO
注意,某个Tag对象的子节点以及子节点里面的内容都不算进string,当一个元素(好比<div>这种)里面只有子节点,自己没有文字的话,获得的就是None。
● BeautifulSoup对象
指代整个文档的对象。能够视为是<html>的对象。其实以前建立的BeautifulSoup对象soup,就是指代整个html文档
● comment对象
用于表明某个元素内的注释
■ 遍历文件树
除了上面提到的一些基本属性,Tag对象(包括BeautifulSoup对象)都含有如下属性:
Tag.contents 将某个Tag的各个子节点(不包括孙和孙如下节点)按照列表的方式输出
Tag.children 返回一个上述列表的迭代器,也只有子节点(没有孙和孙如下节点)
Tag.descendants 返回一个迭代器,内容是全部后辈节点
Tag.strings 返回Tag中全部的文字部分的生成器,保留换行,制表符等空格。至关因而prettify以后去掉全部html标签的文本状态。
Tag.stripped_strings 和上一项相比,再去掉全部空白字符,只保留有实际字符的文本部分。这两个方法经常使用于对被分析网页文本的搜索和处理。
Tag.parent 父节点
Tag.parents 长辈节点的迭代器
Tag.next_sibling 下一个同辈节点(若是没有同辈就返回None,下同)
Tag.previous_sibling 上一个同辈节点
Tag.next_sibilings 以后全部同辈节点的迭代器
Tag.previous_sibilings 以前全部同辈节点的迭代器
//关于同辈节点有一个坑。。在看起来比较美观的HTML文档中,老是有不少换行符合制表符的。而在BS中若是要调用一个同辈节点,那么这些空白的文本节点也都会被算进去。好比:
#<p><span>one</span><span id="main">two</span></p> print soup.find(name="span",attrs={"id":"main"}).previous_sibling #获得的是<span>one</span> #若是处理的是这样一段HTML: #<p> # <span>one</span> # <span id="main">two</span> #</p> print repr(soup.find(name="span",attrs={"id":"main"}).previous_sibling) #获得的是"\n\t"由于在第一个span以前有一段空白文本被当作一个节点了。
然而在经过这个span.parent寻找p或者是经过p.children寻找span的时候,这些空白文本节点都不会被算进去。因此只有在引用同辈节点的时候要注意。
Tag.next_element 下一个元素,包括string对象,子节点,同辈分节点在内,无视辈分的下一个
Tag.previous_element 上一个元素,说明同上
Tag.next_elements next_element的迭代器
Tag.previous_elements previous_element的迭代器
■ 检索文件树方法
● Tag.find_all(name,attr,recursive,text,**kwargs) 方法。功能是检索Tag内全部后辈节点,并判断是否符合某种条件,最后返回一个列表
1. name参数
name参数能够直接写Tag.name。好比find_all("p"),find_all("div")等
也能够写正则表达式(re.compile以后的对象)。好比find_all(re.compile("^b"))
也能够写列表,好比find_all(['a','p'])
甚至能够写一个函数对象,这时就要本身定义这个函数了。这个函数要接收一个Tag对象来做为参数,并最终返回True或者False来告诉find_all这个对象该不应被find进去
2. attr参数
attr参数能够指定一个字典的形式来过滤,好比find_all(attrs={'id':'testid'})就是找到全部id是testid的元素
3. text参数
用于搜索字串内容。也能够支持name参数中那几种写的形式。注意,返回的不是对象的列表,而是文本的列表。当name和text的参数同时出现的话,text会做为name的一个附加条件,返回的仍是带标签的列表。
4. recursive参数
默认是True,可改为False放弃递归进子辈如下子节点。只检索第一级的子节点。
5. limit参数
有时候文档太大了,检索全部元素很费时间,limit能够指定一个数值,当检索找到了这个数量的目标以后就中止检索
● Tag.find方法:参数和find_all一致,只不过其返回的不是一个列表,而是找到第一个就返回了。
● Tag.find_parents Tag.find_parent
Tag.find_next_sibilings Tag.find_next_sibiling
Tag.find_previous_sibilings Tag.find_previous_sibiling
Tag.find_all_next Tag.find_next
Tag.find_all_previous Tag.find_previous
以上全部方法,每行前一个和后一个的关系就是find_all和find的关系。而每一行至关因而为检索指定了一个大体的范围。好比说find_all和find是在全部后辈节点中检索的话,那么find_parents和find_parent就是在全部长辈节点中寻找,find_next_sibilings和find_next_sibiling就是在全部后面的同辈节点中寻找等等
● Tag.select("selector") 能够借助select方法来肯定一个或多个特定的元素,默认查找所有符合的元素并返回一个列表。selector的语法就是jQuery里面selector的语法。这个方法仍是比较实用的。与之相对的有select_one方法,只返回第一个查找到的元素。
总的来讲,不论是经过一个节点,遍历文件树的方法来找到想要得到的节点对象,仍是经过检索方法来定位一个节点对象,都是寻找对象的一种方法。很难说哪一种最好哪一种很差,应该要灵活运用。