beautifulsoup教程
BeautifulSoup4是爬⾍必学的技能。BeautifulSoup最主要的功能是从⽹页抓取数据,Beautiful Soup⾃动将输⼊⽂档转换为Unicode编码,输出⽂档转换为utf-8编码。BeautifulSoup⽀持Python标准库中的HTML解析器,还⽀持⼀些第三⽅的解析器,如果我们不安装它,则 Python 会使⽤ Python默认的解析器,lxml 解析器更加强⼤,速度更快,推荐使⽤lxml 解析器。
⼀、BeautifulSoup4简介
BeautifulSoup4和 lxml ⼀样,Beautiful Soup 也是⼀个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。BeautifulSoup⽀持Python标准库中的HTML解析器,还⽀持⼀些第三⽅的解析器,如果我们不安装它,则 Python 会使⽤ Python默认的解析器,lxml 解析器更加强⼤,速度更快,推荐使⽤lxml 解析器。
Beautiful Soup⾃动将输⼊⽂档转换为Unicode编码,输出⽂档转换为utf-8编码。你不需要考虑编码⽅式,除⾮⽂档没有指定⼀个编码⽅式,这时,Beautiful Soup就不能⾃动识别编码⽅式了。然后,你仅仅需要说明⼀下原始编码⽅式就可以了。
⼆、BeautifulSoup4主要解析器,以及优缺点:
[外链图⽚转存失败,源站可能有防盗链机制,建议将图⽚保存下来直接上传(img-8f6XgNXi-1598587320926)
(beautifulsoup%E6%95%99%E7%A8%8B/4CD4F032-4D45-4F82-8C15-0C791A2C34CA.png)]
三、BeautifulSoup4简单使⽤
假设有这样⼀个Html,具体内容如下:
1.  <!DOCTYPE html>
2.  <html>
3.
4.  <head>
5.      <meta content="text/html;charset=utf-8" http-equiv="content-type"/>
6.      <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
7.      <meta content="always" name="referrer"/>
8.      <link href="ss1.bdstatic/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>
9.      <title>百度⼀下,你就知道</title>
10. </head>
11.
12. <body link="#0000cc">
13.  <div id="wrapper">
14.    <div id="head">
15.        <div class="head_wrapper">
16.          <div id="u1">
17.            <a class="mnav" href="news.baidu" name="tj_trnews">新闻</a>
18.            <a class="mnav" href="www.hao123" name="tj_trhao123">hao123 </a>
19.            <a class="mnav" href="map.baidu" name="tj_trmap">地图</a>
20.            <a class="mnav" href="v.baidu" name="tj_trvideo">视频</a>
21.            <a class="mnav" href="tieba.baidu" name="tj_trtieba">贴吧</a>
22.            <a class="bri" href="//www.baidu/more/" name="tj_briicon" >更多产品</a>
23.          </div>
24.        </div>
25.    </div>
26.  </div>
27. </body>
28.
29. </html>
创建beautifulsoup4对象:
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.  bs = BeautifulSoup(html,"html.parser") # 缩进格式
5.
6.  print(bs.prettify()) # 获取title标签的所有内容
7.  print(bs.title) # 获取title标签的名称
8.  print(bs.title.name) # 获取title标签的⽂本内容
9.  print(bs.title.string) # 获取head标签的所有内容
10. print(bs.head) # 获取第⼀个div标签中的所有内容
11. print(bs.div) # 获取第⼀个div标签的id的值
12. print(bs.div["id"]) # 获取第⼀个a标签中的所有内容
13. print(bs.a) # 获取所有的a标签中的所有内容
14. print(bs.find_all("a")) # 获取id="u1"
15. print(bs.find(id="u1")) # 获取所有的a标签,并遍历打印a标签中的href的值
16.
17. for item in bs.find_all("a"):
18.    ("href")) # 获取所有的a标签,并遍历打印a标签的⽂本值
19.
20. for item in bs.find_all("a"):
21.    _text())
四、BeautifulSoup4四⼤对象种类
BeautifulSoup4将复杂HTML⽂档转换成⼀个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag
NavigableString
BeautifulSoup
Comment
4.1 、Tag
Tag通俗点讲就是HTML中的⼀个个标签,例如:
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.  bs = BeautifulSoup(html,"html.parser")
5.
6.  # 获取title标签的所有内容
7.  print(bs.title)
8.
9.  # 获取head标签的所有内容
10. print(bs.head)
11.
12. # 获取第⼀个a标签的所有内容
13. print(bs.a)
14.
15. # 类型
16. print(type(bs.a))
我们可以利⽤ soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。但是注意,它查的是在所有内容中的第⼀个符合要求的标签。
对于 Tag,它有两个重要的属性,是 name 和 attrs:
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.  bs = BeautifulSoup(html,"html.parser")
5.
6.  # [document] #bs 对象本⾝⽐较特殊,它的 name 即为 [document]
7.  print(bs.name)
8.
9.  # head #对于其他内部标签,输出的值便为标签本⾝的名称
10. print(bs.head.name)
11.
12. # 在这⾥,我们把 a 标签的所有属性打印输出了出来,得到的类型是⼀个字典。
13. print(bs.a.attrs)
14.
15. #还可以利⽤get⽅法,传⼊属性的名称,⼆者是等价的
16. print(bs.a['class']) # 等价 ('class')
17.
18. # 可以对这些属性和内容等等进⾏修改
19. bs.a['class'] = "newClass"
20. print(bs.a)
21.
22. # 还可以对这个属性进⾏删除
23. del bs.a['class']
24. print(bs.a)
4.2、NavigableString
既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的⽂字怎么办呢?很简单,⽤ .string 即可,例如:
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.
5.  bs = BeautifulSoup(html,"html.parser")
6.
7.  print(bs.title.string)
8.  print(type(bs.title.string))
4.3、BeautifulSoup
BeautifulSoup对象表⽰的是⼀个⽂档的内容。⼤部分时候,可以把它当作 Tag 对象,是⼀个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性,例如:
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.
5.  bs = BeautifulSoup(html,"html.parser")
6.
7.  print(type(bs.name))
8.  print(bs.name)
9.  print(bs.attrs)
4.4、Comment
Comment 对象是⼀个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.
5.  bs = BeautifulSoup(html,"html.parser")
6.  print(bs.a)
7.  # 此时不能出现空格和换⾏符,a标签如下:
8.  # <a class="mnav" href="news.baidu" name="tj_trnews"><!--新闻--></a>
9.
10. print(bs.a.string) # 新闻
11.
12. print(type(bs.a.string)) # <class 'bs4.element.Comment'>
五、遍历⽂档树
5.1、.contents:
获取Tag的所有⼦节点,返回⼀个list
1.  # tag的.content 属性可以将tag的⼦节点以列表的⽅式输出
2.  print(ts)
3.
4.  # ⽤列表索引来获取它的某⼀个元素
5.  print(ts[1])
5.2、.children:
获取Tag的所有⼦节点,返回⼀个⽣成器
1.  for child in  bs.body.children:
2.      print(child)
5.3、.descendants:获取Tag的所有⼦孙节点
5.4、.strings:如果Tag包含多个字符串,即在⼦孙节点中有内容,可以⽤此获取,⽽后进⾏遍历
5.5、.stripped_strings:与strings⽤法⼀致,只不过可以去除掉那些多余的空⽩内容
5.6、.parent:获取Tag的⽗节点
5.7、.parents:递归得到⽗辈元素的所有节点,返回⼀个⽣成器
5.8、.previous_sibling:获取当前Tag的上⼀个节点,属性通常是字符串或空⽩,真实结果是当前标签与上⼀个标签之间的顿号和换⾏符5.9、.next_sibling:获取当前Tag的下⼀个节点,属性通常是字符串或空⽩,真是结果是当前标签与下⼀个标签之间的顿号与换⾏符
5.10、.previous_siblings:获取当前Tag的上⾯所有的兄弟节点,返回⼀个⽣成器
5.11、.next_siblings:获取当前Tag的下⾯所有的兄弟节点,返回⼀个⽣成器
5.12、.previous_element:获取解析过程中上⼀个被解析的对象(字符串或tag),可能与previous_sibling相同,但通常是不⼀样的
5.13、.next_element:获取解析过程中下⼀个被解析的对象(字符串或tag),可能与next_sibling相同,但通常是不⼀样的
5.14、.previous_elements:返回⼀个⽣成器,可以向前访问⽂档的解析内容
5.15、.next_elements:返回⼀个⽣成器,可以向后访问⽂档的解析内容
5.16、.has_attr:判断Tag是否包含属性
六、搜索⽂档树
6.1、find_all(name, attrs, recursive, text, **kwargs)
在上⾯的栗⼦中我们简单介绍了find_all的使⽤,接下来介绍⼀下find_all的更多⽤法-过滤器。这些过滤器贯穿整个搜索API,过滤器可以被⽤在tag的name中,节点的属性等。
(1)name参数:
字符串过滤:会查与字符串完全匹配的内容
1.  a_list = bs.find_all("a")
2.  print(a_list)
正则表达式过滤:如果传⼊的是正则表达式,那么BeautifulSoup4会通过search()来匹配内容
1.  from bs4 import BeautifulSoup
2.  import re
3.  file = open('./aa.html', 'rb')
4.  html = ad()
5.
6.  bs = BeautifulSoup(html,"html.parser")
7.
8.  t_list = bs.find_all(repile("a"))
9.  for item in t_list:
10.    print(item)
列表:如果传⼊⼀个列表,BeautifulSoup4将会与列表中的任⼀元素匹配到的节点返回
1.  t_list = bs.find_all(["meta","link"])
2.  for item in t_list:
3.      print(item)
⽅法:传⼊⼀个⽅法,根据⽅法来匹配
1.  from bs4 import BeautifulSoup
2.  file = open('./aa.html', 'rb')
3.  html = ad()
4.
5.  bs = BeautifulSoup(html,"html.parser")
6.
7.  def name_is_exists(tag):
8.      return tag.has_attr("name")
9.
10. t_list = bs.find_all(name_is_exists)
11. for item in t_list:
12.    print(item)
(2)kwargs参数:
1.  from bs4 import BeautifulSoup
2.  import re
3.  file = open('./aa.html', 'rb')
4.  html = ad()
5.
6.  bs = BeautifulSoup(html,"html.parser")
7.
8.  # 查询id=head的Tag
9.  t_list = bs.find_all(id="head") print(t_list)
10.
11. # 查询href属性包含ss1.bdstatic的Tag
12. t_list = bs.find_all(href=repile("news.baidu"))
13. print(t_list)
14.
15. # 查询所有包含class的Tag(注意:class在Python中属于关键字,所以加_以⽰区别)
16. t_list = bs.find_all(class_=True)
17. for item in t_list:
18.    print(item)
(3)attrs参数:
并不是所有的属性都可以使⽤上⾯这种⽅式进⾏搜索,⽐如HTML的data-*属性:
t_list = bs.find_all(data-foo="value")
如果执⾏这段代码,将会报错。我们可以使⽤attrs参数,定义⼀个字典来搜索包含特殊属性的tag:
1.  t_list = bs.find_all(attrs={"data-foo":"value"})
python 正则表达式 空格
2.  for item in t_list:
3.      print(item)
(4)text参数:
通过text参数可以搜索⽂档中的字符串内容,与name参数的可选值⼀样,text参数接受字符串,正则表达式,列表
1.  from bs4 import BeautifulSoup
2.  import re
3.  file = open('./aa.html', 'rb')
4.  html = ad()
5.
6.  bs = BeautifulSoup(html, "html.parser")
7.
8.  t_list = bs.find_all(attrs={"data-foo": "value"})
9.  for item in t_list:
10.    print(item)
11.
12. t_list = bs.find_all(text="hao123")
13. for item in t_list:
14.    print(item)
15.
16. t_list = bs.find_all(text=["hao123", "地图", "贴吧"])
17. for item in t_list:
18.    print(item)
19.
20. t_list = bs.find_all(text=repile("\d"))
21. for item in t_list:
22.    print(item)
当我们搜索text中的⼀些特殊属性时,同样也可以传⼊⼀个⽅法来达到我们的⽬的:
1.  def length_is_two(text):
2.      return text and len(text) == 2
3.
4.  t_list = bs.find_all(text=length_is_two)
5.  for item in t_list:
6.      print(item)
(5)limit参数:
可以传⼊⼀个limit参数来限制返回的数量,当搜索出的数据量为5,⽽设置了limit=2时,此时只会返回前2个数据
1.  from bs4 import BeautifulSoup
2.  import re
3.  file = open('./aa.html', 'rb')
4.  html = ad()
5.
6.  bs = BeautifulSoup(html, "html.parser")
7.
8.  t_list = bs.find_all("a",limit=2)
9.  for item in t_list:
10.    print(item)
find_all除了上⾯⼀些常规的写法,还可以对其进⾏⼀些简写:
1.  # 两者是相等的
2.  # t_list = bs.find_all("a") => t_list = bs("a")
3.  t_list = bs("a") # 两者是相等的
4.  # t_list = bs.a.find_all(text="新闻") => t_list = bs.a(text="新闻")
5.  t_list = bs.a(text="新闻")
6.2、find()
find()将返回符合条件的第⼀个Tag,有时我们只需要或⼀个Tag时,我们就可以⽤到find()⽅法了。当然了,也可以使⽤find_all()⽅法,传⼊⼀个limit=1,然后再取出第⼀个值也是可以的,不过未免繁琐。
1.  from bs4 import BeautifulSoup
2.  import re
3.  file = open('./aa.html', 'rb')
4.  html = ad()
5.
6.  bs = BeautifulSoup(html, "html.parser")
7.
8.  # 返回只有⼀个结果的列表
9.  t_list = bs.find_all("title",limit=1)
10. print(t_list)
11.
12. # 返回唯⼀值
13. t = bs.find("title")
14. print(t)
15.
16. # 如果没有到,则返回None
17. t = bs.find("abc") print(t)
从结果可以看出find_all,尽管传⼊了limit=1,但是返回值仍然为⼀个列表,当我们只需要取⼀个值时,远不如find⽅法⽅便。但
是如果未搜索到值时,将返回⼀个None
在上⾯介绍BeautifulSoup4的时候,我们知道可以通过bs.div来获取第⼀个div标签,如果我们需要获取第⼀个div下的第⼀个div,
我们可以这样:
1.  t = bs.div.div
2.
3.  # 等价于
4.  t = bs.find("div").find("div")
七、CSS选择器
BeautifulSoup⽀持发部分的CSS选择器,在Tag获取BeautifulSoup对象的.select()⽅法中传⼊字符串参
数,即可使⽤CSS选择器的语法到Tag:
7.1、通过标签名查
1.  print(bs.select('title'))
2.
3.  print(bs.select('a'))
7.2、通过类名查
1.  print(bs.select('.mnav'))
7.3、通过id查
1.  print(bs.select('#u1'))
7.4、组合查
1.  print(bs.select('div .bri'))
7.5、属性查
1.  print(bs.select('a[class="bri"]'))
2.  print(bs.select('a[href="tieba.baidu"]'))
7.6、直接⼦标签查
1.  t_list = bs.select("head > title")