人生苦短,我用 Pythonhtml
前文传送门:html5
小白学 Python 爬虫(1):开篇python
小白学 Python 爬虫(2):前置准备(一)基本类库的安装git
小白学 Python 爬虫(3):前置准备(二)Linux基础入门github
小白学 Python 爬虫(4):前置准备(三)Docker基础入门数据库
小白学 Python 爬虫(5):前置准备(四)数据库基础浏览器
小白学 Python 爬虫(6):前置准备(五)爬虫框架的安装框架
小白学 Python 爬虫(10):Session 和 Cookies
小白学 Python 爬虫(11):urllib 基础使用(一)
小白学 Python 爬虫(12):urllib 基础使用(二)
小白学 Python 爬虫(13):urllib 基础使用(三)
小白学 Python 爬虫(14):urllib 基础使用(四)
小白学 Python 爬虫(15):urllib 基础使用(五)
小白学 Python 爬虫(16):urllib 实战之爬取妹子图
小白学 Python 爬虫(17):Requests 基础使用
小白学 Python 爬虫(18):Requests 进阶操做
首先固然是各类资料地址敬上:
先看下官方对本身的介绍:
Beautiful Soup 提供一些简单的、 Python 式的函数来处理导航、搜索、修改分析树等功能。它是一个工具箱,经过解析文档为用户提供须要抓取的数据,由于简单,因此不须要多少代码就能够写出一个完整的应用程序。
Beautiful Soup 自动将输入文档转换为 Unicode 编码,输出文档转换为 UTF-8 编码。你不须要考虑编码方式,除非文档没有指定一个编码方式,这时你仅仅须要说明一下原始编码方式就能够了。
Beautiful Soup 已成为和 lxml 、 html6lib 同样出色的 Python 解释器,为用户灵活地提供不一样的解析策略或强劲的速度。
讲人话就是 Beautiful Soup 是一个很是好用、速度又快的 HTML 或 XML 的解析库。
Beautiful Soup 在解析时实际上依赖解析器,它除了支持Python标准库中的HTML解析器外,还支持一些第三方解析器。下表列出了主要的解析器,以及它们的优缺点(如下内容来自:https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/# ):
解析器 | 使用方法 | 优点 | 劣势 |
---|---|---|---|
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格式的文档 | 速度慢、不依赖外部扩展 |
推荐使用 lxml 做为解析器,由于效率更高。在 Python2.7.3 以前的版本和 Python3 中 3.2.2 以前的版本,必须安装 lxml 或 html5lib ,由于那些 Python 版本的标准库中内置的 HTML 解析方法不够稳定。
提示: 若是一段 HTML 或 XML 文档格式不正确的话,那么在不一样的解析器中返回的结果多是不同的,查看 解析器之间的区别 了解更多细节。
爬取对象仍是小编的我的博客(小编看着博客的流量在暗暗心痛)。最基本的,仍是先打印首页的 HTML 源码,使用的类库为 Requests + bs4。
import requests from bs4 import BeautifulSoup response = requests.get('https://www.geekdigging.com/') soup = BeautifulSoup(response.content, "html5lib") print(soup.prettify())
结果就不贴了,太长,浪费你们翻页的时间。
首先先解释一下这里为何选择了 html5lib
的解析器而不是 lxml 的解析器,由于通过小编测试 lxml 的解析器没法解析某些 HTML 标签,通过小编的测试,使用 Python 标准库或者 html5lib
解析器都无此问题,因此这里选择使用 Python 标准库。
上面这段代码主要是调用了 prettify()
,这个方法的主要做用是把要解析的字符串以标准的缩进格式输出。值得注意的是,这里的输出会自动更正 HTML 的格式,可是这一步并非由 prettify()
这个方法来作的,而是在初始化 BeautifulSoup 时就完成了。
咱们使用 Beautiful Soup 的目的是什么?固然是要选择咱们须要的节点,并从节点中提取出咱们须要的数据。
Beautiful Soup 将复杂 HTML 文档转换成一个复杂的树形结构,每一个节点都是 Python 对象,全部对象能够概括为4种: Tag
, NavigableString
, BeautifulSoup
, Comment
。
咱们直接调用节点的名称就能够选择节点元素,再调用 string 属性就能够获得节点内的文本了,这种选择方式速度很是快。
print(soup.title) print(type(soup.title)) print(soup.title.string) print(soup.a)
结果以下:
<title>极客挖掘机</title> <class 'bs4.element.Tag'> 极客挖掘机 <a class="logo" href="/"> <img src="/favicon.jpg" style="margin-right: 10px;"/>极客挖掘机 </a>
能够看到,咱们这里直接输出的 title
节点,它的类型是 bs4.element.Tag
,而且使用 string 属性,直接获得了该节点的内容。
这里咱们打印了 a
节点,能够看到,只打印出来了第一个 a
节点,后面的节点并未打印,说明当有多个节点时,这种方式只能得到第一个节点。
每一个 tag 都有本身的名字,经过 .name
来获取:
tag = soup.section print(tag.name)
结果以下:
section
一个 tag 可能有不少个属性, tag 的属性的操做方法与字典相同:
print(tag['class'])
结果以下:
['content-wrap']
也能够直接”点”取属性, 好比: .attrs
:
print(tag.attrs)
结果以下:
{'class': ['content-wrap']}
能够利用 string
属性获取节点元素包含的文本内容,好比要获取 title
标签的内容:
print(soup.title.string)
结果以下:
极客挖掘机
在上面的示例中,咱们的信息都是从经过 tag 的属性得到的,固然 tag 是能够继续嵌套的选择下去,好比咱们刚才获取了第一个 a
标签,咱们能够继续获取其中的 img
标签:
print(soup.a.img) print(type(soup.a.img)) print(soup.a.img.attrs)
结果以下:
<img src="/favicon.jpg" style="margin-right: 10px;"/> <class 'bs4.element.Tag'> {'src': '/favicon.jpg', 'style': 'margin-right: 10px;'}
能够看到咱们在 a
标签上继续选择的 img
标签,它的类型依然是 bs4.element.Tag
,而且咱们成功的获取了 img
标签的属性值,也就是说,咱们在 Tag 类型的基础上再次选择获得的依然仍是 Tag 类型,因此这样就能够作嵌套选择了。
在选择节点的时候,咱们不多能够一步到位,直接选到所须要的节点,这就须要咱们先选中其中的某一个节点,再已它为基准,再选择它的子节点、父节点或者兄弟节点。
获取子节点,咱们能够选择使用 contents 属性,示例以下:
print(soup.article.contents)
结果太长了,小编就不贴了,这里输出了第一个 article
的全部节点,而且返回结果是列表形式。 article
节点里既包含文本,又包含节点,最后会将它们以列表形式统一返回。
这里须要注意的是,列表中的每一个元素都是 article
的直接子节点,并无将再下一级的元素列出来。而使用 children
也能够获得相同的效果。
for child in enumerate(soup.article.children): print(child)
结果获得的仍是相同的的 HTML 文本,这里调用了 children
属性来选择,返回结果是生成器类型。
想要获得全部的孙子节点的话,可使用 descendants
:
for i, child in enumerate(soup.article.descendants): print(i, child)
获取父节点可使用 parent
属性,示例以下:
print(soup.title.parent)
结果有些长,就不贴了,各位同窗能够自行尝试一下。
想要获取兄弟节点可使用属性 next_sibling
和 previous_sibling
。
print('next_sibling:', soup.title.next_sibling) print('previous_sibling:', soup.title.previous_sibling) print('next_siblings:', soup.title.next_siblings) print('previous_siblings:', soup.title.previous_siblings)
结果以下:
next_sibling: previous_sibling: next_siblings: <generator object PageElement.next_siblings at 0x00000183342C5D48> previous_siblings: <generator object PageElement.previous_siblings at 0x00000183342C5D48>
能够看到, next_sibling 和 previous_sibling 分别获取节点的下一个和上一个兄弟元素,在这里并无获取到值,而是获取了不少的空行,这个是在初始化 BeautifulSoup 的时候初始化出来的,而 next_siblings 和 previous_siblings 则分别返回全部前面和后面的兄弟节点的生成器。
本系列的全部代码小编都会放在代码管理仓库 Github 和 Gitee 上,方便你们取用。