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 #将源码转为文本赋值给html
soup=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 BeautifulSoup
soup = 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的子节点进行循环
-
```python
for 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.title
title_tag
# <title>The Dormouse's story</title>
title_tag.parent
# <head><title>The Dormouse's story</title></head>
Tag.parents 可以递归得到元素的所有父辈节点
link = soup.a
link
# <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 re
for 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.b
tag.name = "blockquote"
tag['class'] = 'verybold'
tag['id'] = 1
tag
# <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.a
tag.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.a
tag.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.a
i_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.a
soup.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.a
new_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 BeautifulSoup
import requests
url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"
res=requests.get(url)
res.encoding="utf-8" #转为utf-u解码
html=res.text #将源码转为文本赋值给html
soup=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'])