By 平常学python
这是平常学python的第16篇原创文章
通过了前面几篇文章的学习,估计你已经会爬很多中小型网站了。可是有人说,前面的正则很难唉,学很差。正则的确很难,有人说过:若是一个问题用正则解决,那么就变成了两个问题。因此说学不会是很正常的,不怕,除了正则,咱们还能够用另一个强大的库来解析html。因此,今天的主题就是来学习这个强大的库--BeautifulSoup,不过正则仍是须要多多练习下的。css
由于是第三方库因此咱们须要下载,在命令行敲下如下代码进行下载html
pip install beautifulsoup4
安装第三方解析库html5
pip install lxml pip install html5lib
若是不知道有什么用请往下看python
这里官方推荐解析库为lxml,由于它的效率高。下面都是用lxml解析库来进行解析的。浏览器
本文是进行解析豆瓣图书首页https://book.douban.com/markdown
1)建立bs对象python爬虫
from bs4 import BeautifulSoup import requests response = requests.get('https://book.douban.com/').text # print(response) # 建立bs对象 soup = BeautifulSoup(response, 'lxml') # 使用到了lxml解析库
2)获取相关标签
标签:ide
<a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
上面的a就是一个标签名字,最简单的就是<a></a>这样,能够简单理解为<>里面的第一个单词就是标签名学习
# 获取标签 print(soup.li) # 这个只是获取第一个li标签 # 结果 <li class=""> <a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a> </li>
3)获取标签的名字和内容
标签的名字和内容:网站
<a >豆瓣</a>
如上面所说,a就是标签名字,而两个标签之中所夹杂的内容就是咱们所说的内容,如上,豆瓣就是该标签的内容
# 获取标签名字 print(soup.li.name) # 获取标签内容 print(soup.li.string) # 这个只能是这个标签没有子标签才能正确获取,不然会返回None # 结果 li None
因为这个li标签里面还有个子标签,因此它的文本内容为None
下面这个就能够获取它的文本内容
# 获取标签内的标签 print(soup.li.a) print(soup.li.a.string) # 这个标签没有子标签因此能够获取到内容 # 结果 <a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a> 豆瓣
4)获取标签属性,有两种方法
标签属性:
<a rel="nofollow" href="https://www.douban.com" target="_blank">豆瓣</a>
能够简单理解为属性就是在标签名字旁边并且在前一个<>符号里面的,还有是有等号来进行体现的。因此上面的href就是标签属性名字,等号右边的就是属性的值,上面的值是个网址
# 获取标签属性 print(soup.li.a['href']) # 第一种 print(soup.li.a.attrs['href']) # 第二种 # 结果 https://www.douban.com https://www.douban.com
5)获取标签内的子标签
子标签:
<li><a>豆瓣</a></li>
好比咱们如今获取的li标签,因此a标签就是li标签的子标签
# 获取标签内的标签 print(soup.li.a) # 结果 <a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
6)获取全部子节点
子节点:这个和子标签是差很少的,只不过这里是获取一个标签下的全部子标签,上面的只是获取最接近该标签的子标签
# 获取子节点 print(soup.div.contents) # 返回一个列表 第一种方法 for n, tag in enumerate(soup.div.contents): print(n, tag) # 结果 ['\n', <div class="bd"> <div class="top-nav-info"> <a class="nav-login" href="https://www.douban.com/accounts/login?source=book" rel="nofollow">登陆</a> ... 0 1 <div class="bd"> <div class="top-nav-info"> ...
这个是获取div下的全部子节点,.content就是获取子节点的属性
7)第二种方法获取全部子节点
# 第二种方法 print(soup.div.children) # 返回的是一个迭代器 for n, tag in enumerate(soup.div.children): print(n, tag)
这个是用.children获取全部的子节点,这个方法返回的是一个迭代器
8)获取标签的子孙节点,就是全部后代
子孙节点:
<ul> <li> <a>豆瓣</a> </li> </ul>
从上面知道,li标签是ul标签的子标签,a标签是li标签的子标签,若此时咱们获取的是ul标签,因此li标签和a标签都是ul标签的子孙节点
# 获取标签的子孙节点 print(soup.div.descendants) # 返回的是一个迭代器 for n, tag in enumerate(soup.div.descendants): print(n, tag) # 结果 ... <generator object descendants at 0x00000212C1A1E308> 0 1 <div class="bd"> <div class="top-nav-info"> <a class="nav-login" href="https://www.douban.com/accounts/login?source=book" rel="nofollow">登陆</a> ...
这里用到了.descendants属性,获取的是div标签的子孙节点,并且返回结果是一个迭代器
9)获取父节点和全部祖先节点
既然有了子节点和子孙节点,反过来也是有父节点和祖先节点的,因此都很容易理解的
# 获取父节点 print(soup.li.parent) # 返回整个父节点 # 获取祖先节点 print(soup.li.parents) # 返回的是一个生成器 for n, tag in enumerate(soup.li.parents): print(n, tag) .parent属性是获取父节点,返回来的是整个父节点,里面包含该子节点。.parents就是获取全部的祖先节点,返回的是一个生成器
10)获取兄弟节点
兄弟节点:
<ul> <li> <a>豆瓣1</a> </li> <li> <a>豆瓣2</a> </li> <li> <a>豆瓣3</a> </li> </ul>
好比上面的html代码,里面的li标签都是ul标签的子节点,而li标签都是处于同级的,因此上面的li标签都是各自的兄弟。这就是兄弟节点。
# 获取兄弟节点 print(soup.li.next_siblings) # 获取该标签的全部同级节点,不包括自己 返回的是一个生成器 for x in soup.li.next_siblings: print(x) # 结果 <generator object next_siblings at 0x000002A04501F308> <li class="on"> <a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-book","uid":"0"}' href="https://book.douban.com">读书</a> </li> ...
.next_siblings属性是获取该标签的全部在他后面的兄弟节点,不包括他自己。同时返回结果也是一个迭代器
同理,既然有获取他的下一个全部兄弟标签,也有获取他前面的全部兄弟标签
soup.li.previous_siblings
若是只是获取一个便可,能够选择把上面的属性后面的s字母去掉便可,以下
soup.li.previous_sibling # 获取前一个兄弟节点
soup.li.next_sibling # 获取后一个兄弟节点
在前面咱们能够获取标签的名字、属性、内容和全部的祖孙标签。可是当咱们须要获取任意一个指定属性的标签仍是有点困难的,因此,此时有了下面这个方法:
soup.find_all( name , attrs , recursive , text , **kwargs )
1)先使用name参数来进行搜索
# 先使用name参数 print(soup.find_all('li')) # 返回一个列表,全部的li标签名字 # 结果 [<li class=""> <a rel="nofollow" data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a> </li>, <li class="on"> ...
这里获取了全部标签名字为li的标签
2)使用name和attrs参数
# 使用name和attrs参数 print(soup.find_all('div', {'class': 'more-meta'})) # 这个对上个进行了筛选,属性参数填的是一个字典类型的 # 结果 [<div class="more-meta"> <h4 class="title"> 刺 </h4> ...
这里搜索了具备属性为class='more-meta'的div标签
3)根据关键字参数来搜索
# 对相关属性进行进行查找也能够这样 print(soup.find_all(class_='more-meta')) # 使用关键字参数,由于class是python关键字,因此关键字参数时须要加多一个下划线来进行区别 # 结果 和上面的结果同样 ...
这里注意,咱们找的是class属性为more-meta的标签,用了关键字参数,可是python里面有class关键字,因此为了避免使语法出错,因此须要在class加个下划线
其余参数的就再也不介绍了,能够自行去官网查看
4)find()方法
此方法与find_all()方法同样,只不过这个方法只是查找一个标签而已,后者是查找全部符合条件的标签。
还有不少相似的方法,用法都差很少,就再也不一一演示了,须要的能够去官网查看
5)select()方法
这个方法是使用css选择器来进行筛选标签的。
css选择器:就是根据标签的名字,id和class属性来选择标签。
若是还不太会的话,能够直接在浏览器上按下f12来查看
位置在箭头所指的位置就是选择器的表达
代码以下
# 还能够用标签选择器来进行筛选元素, 返回的都是一个列表 print(soup.select('ul li div')) # 这个是根据标签名进行筛选 print(soup.select('.info .title')) # 这个是根据class来进行筛选 print(soup.select('#footer #icp')) # 这个是根据id来进行筛选 # 上面的能够进行混合使用 print(soup.select('ul li .cover a img'))
这里的获取属性和文本内容
# 获取属性 for attr in soup.select('ul li .cover a img'): # print(attr.attrs['alt']) # 也能够这样 print(attr['alt']) # 获取标签的内容 for tag in soup.select('li'): print(tag.get_text()) # 里面能够包含子标签,会将子标签的内容连同输出
.get_tex()方法和前面的.string属性有点不同哈,这里的他会获取该标签的全部文本内容,无论有没有子标签
以上的这些都是我的在学习过程当中作的一点笔记。还有点不足,若是有错误的话欢迎大佬指出哈。若是想要查看更多相关用法能够去官方文档查看:http://beautifulsoup.readthedocs.io/zh_CN/latest/
学习参考资料:https://edu.hellobi.com/course/157
若是这篇文章对你有用,点个赞,转个发如何?