1. Beautifulsoup4
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
Beautifulsoup 四种解析器
| 解析器 | 使用方法 | 优势 | 劣势 |
|---|---|---|---|
| Python标准库 | BeautifulSoup(markup, "html.parser") |
Python的内置标准库执行速度适中文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
| lxml HTML 解析器 | BeautifulSoup(markup, "lxml") |
速度快文档容错能力强 | 需要安装C语言库 |
| lxml XML 解析器 | BeautifulSoup(markup, ["lxml-xml"])``BeautifulSoup(markup, "xml") |
速度快唯一支持XML的解析器 | 需要安装C语言库 |
| html5lib | BeautifulSoup(markup, "html5lib") |
最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 | 速度慢不依赖外部扩展 |
2. 构造方法
- BeautifulSoup(html,”html.parser”)
url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"res=requests.get(url)res.encoding="utf-8" #转为utf-u解码html=res.text #将源码转为文本赋值给htmlsoup=BeautifulSoup(html,'html.parser') #对象化html "lxml"
3. 四大对象种类
Tag HTML中的一个个标签
- Name(标签名) 通过 .name获取
- Attributes(属性) 字典获取 tag[“class”] tag.attrs 可以获取整个字典
- Multi-valued attributes(多值属性) 也是字典获取 返回一个列表
- NavigableString 获取标签内部的文字用 .string 即可
- BeautifulSoup 表示的是一个文档的内容
- Comment 是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
4. 遍历文档树
from bs4 import BeautifulSoupsoup = BeautifulSoup(html_doc, 'html.parser')
soup.tag 使用标签名进行遍历 soup.head soup.h2
Tag.contents 获取该标签中所有元素
head_tag.contents []
title_tag = head_tag.contents[0] title_tag
-Tag.children 对tag的子节点进行循环-```pythonfor child in title_tag.children:print(child)
Tag.descendants 可以对所有tag的子孙节点进行递归循环
for child in head_tag.descendants:print(child)
soup.strings 获取tag中的字符串包含子标签
for string in soup.strings:print(repr(string))# u"The Dormouse's story"# u'\n\n'# u"The Dormouse's story"# u'\n\n'# u'Once upon a time there were three little sisters; and their names were\n'# u'Elsie'# u',\n'# u'Lacie'# u' and\n'# u'Tillie'# u';\nand they lived at the bottom of a well.'# u'\n\n'# u'...'# u'\n'
soup.stripped_strings 输出的字符串中可能包含了很多空格或空行,使用
.stripped_strings可以去除多余空白内容:for string in soup.stripped_strings:print(repr(string))# u"The Dormouse's story"# u"The Dormouse's story"# u'Once upon a time there were three little sisters; and their names were'# u'Elsie'# u','# u'Lacie'# u'and'# u'Tillie'# u';\nand they lived at the bottom of a well.'# u'...'
Tag.parent 获取某个元素的父节点
title_tag = soup.titletitle_tag# <title>The Dormouse's story</title>title_tag.parent# <head><title>The Dormouse's story</title></head>
Tag.parents 可以递归得到元素的所有父辈节点
link = soup.alink# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>for parent in link.parents:if parent is None:print(parent)else:print(parent.name)# p# body# html# [document]# None
5. 搜索文档树
- soud.find() 搜索第一个符合条件的标签
- soud.find_all( name , attrs , recursive , string , **kwargs ) 搜索所有符合条件的标签
唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
5.1. 字符串
最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容
soup.find_all('b')# [<b>The Dormouse's story</b>]
5.2. 正则表达式
如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.
import refor tag in soup.find_all(re.compile("^b")):print(tag.name)# body# b
5.3. 列表
如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回
soup.find_all(["a", "b"])# [<b>The Dormouse's story</b>,# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
5.4. keyword 属性值
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
soup.find_all(id='link2') #搜索所有id为link2的标签# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
5.5. 按CSS搜索
class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag
soup.find_all("a", class_="sister")# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名
css_soup = BeautifulSoup('<p class="body strikeout"></p>')css_soup.find_all-0-0-("p", class_="strikeout")# [<p class="body strikeout"></p>]css_soup.find_all("p", class_="body")# [<p class="body strikeout"></p>]
搜索 class 属性时也可以通过CSS值完全匹配
css_soup.find_all("p", class_="body strikeout")# [<p class="body strikeout"></p>]
完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果
soup.find_all("a", attrs={"class": "sister"})# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
5.6. String 参数
通过 string 参数可以搜搜文档中的字符串内容
soup.find_all(string="Elsie")# [u'Elsie']soup.find_all(string=["Tillie", "Elsie", "Lacie"])# [u'Elsie', u'Lacie', u'Tillie']soup.find_all(string=re.compile("Dormouse"))[u"The Dormouse's story", u"The Dormouse's story"]def is_the_only_string_within_a_tag(s):""Return True if this string is the only child of its parent tag.""return (s == s.parent.string)soup.find_all(string=is_the_only_string_within_a_tag)# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
5.7. limit 参数
find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果.
soup.find_all("a", limit=2)# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
5.8. recursive 参数
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
5.9. 父辈节点
find_all() 和 find() 只搜索当前节点的所有子节点,孙子节点等. find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档搜索文档包含的内容
- soud.find_parents()
- soud.find_parents()
6. 修改文档树
Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树
6.1. 修改tag的名称和属性
重命名一个tag,改变属性的值,添加或删除属性
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')tag = soup.btag.name = "blockquote"tag['class'] = 'verybold'tag['id'] = 1tag# <blockquote class="verybold" id="1">Extremely bold</blockquote>del tag['class']del tag['id']tag# <blockquote>Extremely bold</blockquote>
6.2. 修改 .string
给tag的 .string 属性赋值,就相当于用当前的内容替代了原来的内容
如果当前的tag包含了其它tag,那么给它的 .string 属性赋值会覆盖掉原有的所有内容包括子tag
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'soup = BeautifulSoup(markup)tag = soup.atag.string = "New link text."tag# <a href="http://example.com/">New link text.</a>
6.3. append()
Tag.append() 方法想tag中添加内容
soup = BeautifulSoup("<a>Foo</a>")soup.a.append("Bar")soup# <html><head></head><body><a>FooBar</a></body></html>soup.a.contents# [u'Foo', u'Bar']
6.4. clear()
Tag.clear() 方法移除当前tag的内容
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'soup = BeautifulSoup(markup)tag = soup.atag.clear()tag# <a href="http://example.com/"></a>
6.5. extract()
PageElement.extract() 方法将当前tag移除文档树,并作为方法结果返回
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'soup = BeautifulSoup(markup)a_tag = soup.ai_tag = soup.i.extract()a_tag# <a href="http://example.com/">I linked to</a>i_tag# <i>example.com</i>print(i_tag.parent)None
6.6. decompose()
Tag.decompose() 方法将当前节点移除文档树并完全销毁
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'soup = BeautifulSoup(markup)a_tag = soup.asoup.i.decompose()a_tag# <a href="http://example.com/">I linked to</a>
6.7. replace_with()
PageElement.replace_with() 方法移除文档树中的某段内容,并用新tag或文本节点替代它:
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'soup = BeautifulSoup(markup)a_tag = soup.anew_tag = soup.new_tag("b")new_tag.string = "example.net"a_tag.i.replace_with(new_tag)a_tag# <a href="http://example.com/">I linked to <b>example.net</b></a>
7. bs4的简单使用
from bs4 import BeautifulSoupimport requestsurl="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"res=requests.get(url)res.encoding="utf-8" #转为utf-u解码html=res.text #将源码转为文本赋值给htmlsoup=BeautifulSoup(html,'html.parser') #对象化html "lxml"h =soup.find('h2') #寻找文本中 h2标签的内容print(h)h = soup.find('h2').text #只获取h2标签中的内容print(h)a = soup.find('a') #会寻找文本中第一个a标签print(a)print(type(a))a = soup.find('a').attrs #获取a标签中 href以及 target 存放在字典中print(a)print(a['href'])
