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”)
  1. url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"
  2. res=requests.get(url)
  3. res.encoding="utf-8" #转为utf-u解码
  4. html=res.text #将源码转为文本赋值给html
  5. soup=BeautifulSoup(html,'html.parser') #对象化html "lxml"

3. 四大对象种类

  1. Tag HTML中的一个个标签

    1. Name(标签名) 通过 .name获取
    2. Attributes(属性) 字典获取 tag[“class”] tag.attrs 可以获取整个字典
    3. Multi-valued attributes(多值属性) 也是字典获取 返回一个列表
  2. NavigableString 获取标签内部的文字用 .string 即可
  3. BeautifulSoup 表示的是一个文档的内容
  4. Comment 是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。

4. 遍历文档树

  1. from bs4 import BeautifulSoup
  2. soup = BeautifulSoup(html_doc, 'html.parser')
  • soup.tag 使用标签名进行遍历 soup.head soup.h2

  • Tag.contents 获取该标签中所有元素

    • ```python head_tag = soup.head head_tag

head_tag.contents []

title_tag = head_tag.contents[0] title_tag

  1. -
  2. Tag.children tag的子节点进行循环
  3. -
  4. ```python
  5. for child in title_tag.children:
  6. print(child)
  • Tag.descendants 可以对所有tag的子孙节点进行递归循环

      1. for child in head_tag.descendants:
      2. print(child)
  • soup.strings 获取tag中的字符串包含子标签

      1. for string in soup.strings:
      2. print(repr(string))
      3. # u"The Dormouse's story"
      4. # u'\n\n'
      5. # u"The Dormouse's story"
      6. # u'\n\n'
      7. # u'Once upon a time there were three little sisters; and their names were\n'
      8. # u'Elsie'
      9. # u',\n'
      10. # u'Lacie'
      11. # u' and\n'
      12. # u'Tillie'
      13. # u';\nand they lived at the bottom of a well.'
      14. # u'\n\n'
      15. # u'...'
      16. # u'\n'
  • soup.stripped_strings 输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容:

      1. for string in soup.stripped_strings:
      2. print(repr(string))
      3. # u"The Dormouse's story"
      4. # u"The Dormouse's story"
      5. # u'Once upon a time there were three little sisters; and their names were'
      6. # u'Elsie'
      7. # u','
      8. # u'Lacie'
      9. # u'and'
      10. # u'Tillie'
      11. # u';\nand they lived at the bottom of a well.'
      12. # u'...'
  • Tag.parent 获取某个元素的父节点

      1. title_tag = soup.title
      2. title_tag
      3. # <title>The Dormouse's story</title>
      4. title_tag.parent
      5. # <head><title>The Dormouse's story</title></head>
  • Tag.parents 可以递归得到元素的所有父辈节点

      1. link = soup.a
      2. link
      3. # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
      4. for parent in link.parents:
      5. if parent is None:
      6. print(parent)
      7. else:
      8. print(parent.name)
      9. # p
      10. # body
      11. # html
      12. # [document]
      13. # None

5. 搜索文档树

  • soud.find() 搜索第一个符合条件的标签
  • soud.find_all( name , attrs , recursive , string , **kwargs ) 搜索所有符合条件的标签

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.

5.1. 字符串

最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容

  1. soup.find_all('b')
  2. # [<b>The Dormouse's story</b>]

5.2. 正则表达式

如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.

  1. import re
  2. for tag in soup.find_all(re.compile("^b")):
  3. print(tag.name)
  4. # body
  5. # b

5.3. 列表

如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回

  1. soup.find_all(["a", "b"])
  2. # [<b>The Dormouse's story</b>,
  3. # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
  4. # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
  5. # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

5.4. keyword 属性值

如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索

  1. soup.find_all(id='link2') #搜索所有id为link2的标签
  2. # [<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

  1. soup.find_all("a", class_="sister")
  2. # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
  3. # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
  4. # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名

  1. css_soup = BeautifulSoup('<p class="body strikeout"></p>')
  2. css_soup.find_all-0-0-("p", class_="strikeout")
  3. # [<p class="body strikeout"></p>]
  4. css_soup.find_all("p", class_="body")
  5. # [<p class="body strikeout"></p>]

搜索 class 属性时也可以通过CSS值完全匹配

  1. css_soup.find_all("p", class_="body strikeout")
  2. # [<p class="body strikeout"></p>]

完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果

  1. soup.find_all("a", attrs={"class": "sister"})
  2. # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
  3. # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
  4. # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

5.6. String 参数

通过 string 参数可以搜搜文档中的字符串内容

  1. soup.find_all(string="Elsie")
  2. # [u'Elsie']
  3. soup.find_all(string=["Tillie", "Elsie", "Lacie"])
  4. # [u'Elsie', u'Lacie', u'Tillie']
  5. soup.find_all(string=re.compile("Dormouse"))
  6. [u"The Dormouse's story", u"The Dormouse's story"]
  7. def is_the_only_string_within_a_tag(s):
  8. ""Return True if this string is the only child of its parent tag.""
  9. return (s == s.parent.string)
  10. soup.find_all(string=is_the_only_string_within_a_tag)
  11. # [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 的限制时,就停止搜索返回结果.

  1. soup.find_all("a", limit=2)
  2. # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
  3. # <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,改变属性的值,添加或删除属性

  1. soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
  2. tag = soup.b
  3. tag.name = "blockquote"
  4. tag['class'] = 'verybold'
  5. tag['id'] = 1
  6. tag
  7. # <blockquote class="verybold" id="1">Extremely bold</blockquote>
  8. del tag['class']
  9. del tag['id']
  10. tag
  11. # <blockquote>Extremely bold</blockquote>

6.2. 修改 .string

给tag的 .string 属性赋值,就相当于用当前的内容替代了原来的内容

如果当前的tag包含了其它tag,那么给它的 .string 属性赋值会覆盖掉原有的所有内容包括子tag

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. tag = soup.a
  4. tag.string = "New link text."
  5. tag
  6. # <a href="http://example.com/">New link text.</a>

6.3. append()

Tag.append() 方法想tag中添加内容

  1. soup = BeautifulSoup("<a>Foo</a>")
  2. soup.a.append("Bar")
  3. soup
  4. # <html><head></head><body><a>FooBar</a></body></html>
  5. soup.a.contents
  6. # [u'Foo', u'Bar']

6.4. clear()

Tag.clear() 方法移除当前tag的内容

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. tag = soup.a
  4. tag.clear()
  5. tag
  6. # <a href="http://example.com/"></a>

6.5. extract()

PageElement.extract() 方法将当前tag移除文档树,并作为方法结果返回

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4. i_tag = soup.i.extract()
  5. a_tag
  6. # <a href="http://example.com/">I linked to</a>
  7. i_tag
  8. # <i>example.com</i>
  9. print(i_tag.parent)
  10. None

6.6. decompose()

Tag.decompose() 方法将当前节点移除文档树并完全销毁

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4. soup.i.decompose()
  5. a_tag
  6. # <a href="http://example.com/">I linked to</a>

6.7. replace_with()

PageElement.replace_with() 方法移除文档树中的某段内容,并用新tag或文本节点替代它:

  1. markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
  2. soup = BeautifulSoup(markup)
  3. a_tag = soup.a
  4. new_tag = soup.new_tag("b")
  5. new_tag.string = "example.net"
  6. a_tag.i.replace_with(new_tag)
  7. a_tag
  8. # <a href="http://example.com/">I linked to <b>example.net</b></a>

7. bs4的简单使用

  1. from bs4 import BeautifulSoup
  2. import requests
  3. url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"
  4. res=requests.get(url)
  5. res.encoding="utf-8" #转为utf-u解码
  6. html=res.text #将源码转为文本赋值给html
  7. soup=BeautifulSoup(html,'html.parser') #对象化html "lxml"
  8. h =soup.find('h2') #寻找文本中 h2标签的内容
  9. print(h)
  10. h = soup.find('h2').text #只获取h2标签中的内容
  11. print(h)
  12. a = soup.find('a') #会寻找文本中第一个a标签
  13. print(a)
  14. print(type(a))
  15. a = soup.find('a').attrs #获取a标签中 href以及 target 存放在字典中
  16. print(a)
  17. print(a['href'])