人生苦短,我用 Python

前文传送门:

小白学 Python 爬虫(1):开篇

小白学 Python 爬虫(2):前置准备(一)基本类库的安装

小白学 Python 爬虫(3):前置准备(二)Linux基础入门

小白学 Python 爬虫(4):前置准备(三)Docker基础入门

小白学 Python 爬虫(5):前置准备(四)数据库基础

小白学 Python 爬虫(6):前置准备(五)爬虫框架的安装

小白学 Python 爬虫(7):HTTP 基础

小白学 Python 爬虫(8):网页基础

小白学 Python 爬虫(9):爬虫基础

小白学 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 进阶操作

小白学 Python 爬虫(19):Xpath 基操

小白学 Python 爬虫(20):Xpath 进阶

小白学 Python 爬虫(21):解析库 Beautiful Soup(上)

引言

前面一篇我们介绍的选择方法都是通过属性来进行选择的,这种方法使用起来非常简单,但是,如果 DOM 结构比较复杂的话,这种方法就不是那么友好了。

所以 Beautiful Soup 还为我们提供了一些搜索方法,如 find_all()find() , DOM 节点不好直接用属性方法来表示,我们可以直接搜索嘛~~~

find_all()

先看下语法结构:

find_all( name , attrs , recursive , string , **kwargs )

find_all() 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件。

name

name 参数可以查找所有名字为 name 的 tag ,字符串对象会被自动忽略掉。

from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p> <p class="story">...</p>
""" soup = BeautifulSoup(html_doc, 'lxml') print(soup.find_all(name = "a"))
print(type(soup.find_all(name = "a")[0]))

结果如下:

[<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 'bs4.element.Tag'>

这次的示例换成了字符串,主要是为了各位同学看起来方便,再也不用去对照着图片看了。

这个示例我们使用了 find_all() 方法,并且传入了 name 参数,值为 a ,含义是我们要查找所有的 <a> 节点,可以看到,返回的结果数据类型是列表,长度为 3 ,并且元素类型为 bs4.element.Tag

因为元素类型为 bs4.element.Tag ,我们可以通过前一篇文章介绍的属性直接获取其中的内容:

for a in soup.find_all(name = "a"):
print(a.string)

结果如下:

Elsie
Lacie
Tillie

attrs

除了可以通过 name 进行搜索,我们还可以通过属性进行查询:

print(soup.find_all(attrs={'id': 'link1'}))
print(soup.find_all(attrs={'id': 'link2'}))
print(type(soup.find_all(attrs={'id': 'link1'})))
print(type(soup.find_all(attrs={'id': 'link2'})))

结果如下:

[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
<class 'bs4.element.ResultSet'>
<class 'bs4.element.ResultSet'>

这个示例我们传入的是 attrs 参数,参数的数据类型是字典。

string

这个参数可用来匹配节点的文本,传入的形式可以是字符串,可以是正则表达式对象:

import re

print(soup.find_all(text=re.compile('sisters')))

结果如下:

['Once upon a time there were three little sisters; and their names were\n']

keyword

如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字 tag 的属性来搜索,比如下面的示例我们直接搜索 idlink 的节点和 classtitle 的节点:

print(soup.find_all(id='link1'))
print(soup.find_all(class_='title'))

结果如下:

[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
[<p class="title"><b>The Dormouse's story</b></p>]

当然,我们也可以使用多个指定名字的参数同时过滤 tag 的多个属性:

print(soup.find_all(href=re.compile("elsie"), id='link1'))

结果如下:

[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

有些 tag 属性在搜索不能使用,比如 HTML5 中的 data-* 属性,这时就需要用到上面介绍过的 attrs 参数了。

find()

find()find_all() 非常的像,只不过 find() 不再像 find_all() 一样直接返回所有的匹配节点,而是只返回第一个匹配的元素。举几个简单的栗子:

print(soup.find(name = "a"))
print(type(soup.find(name = "a")))

结果如下:

<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
<class 'bs4.element.Tag'>

其余的查询方法各位同学可以参考官方文档,小编这里简单列举一下:

  • find_parents()find_parent() : 用来搜索当前节点的父辈节点。
  • find_next_siblings()find_next_sibling() : 前者返回后面所有的兄弟节点,后者返回后面第一个兄弟节点。
  • find_previous_siblings()find_previous_sibling() : 前者返回前面所有的兄弟节点,后者返回前面第一个兄弟节点。
  • find_all_next()find_next() :前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。
  • find_all_previous()find_previous() :前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。

CSS

Beautiful Soup 除了提供前面这些属性选择、搜索方法等方式来获取节点,还提供了另外一种选择器 —— CSS 选择器。

如果对 CSS 选择器不熟的话,可以参考:https://www.w3school.com.cn/css/index.asp

使用 CSS 选择器方法非常简单,只需要调用 select() 方法,传入相应的 CSS 选择器即可,还是写几个简单的示例:

print(soup.select('#link1'))
print(type(soup.select('#link1')[0]))
print(soup.select('.story .sister'))

结果如下:

<class 'bs4.element.Tag'>
[<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>]

可以看到,我们使用 CSS 选择器获得的结果同样会是一个列表,并且里面的元素同样是 bs4.element.Tag ,这就意味着我们可以使用它的属性来获取对应的信息。

小结

Beautiful Soup 就这么简单的介绍完了,稍微做点小总结:

  • 在选择解析器的时候尽量选择 lxml ,官方推荐,据说是快。
  • 节点属性筛选虽然简单但是功能有点弱鸡。
  • find_all() 和 find() 其实可以很方便的帮助我们完成绝大多数的工作。
  • CSS 选择器推荐有经验的同学使用,毕竟嘛,选择 DOM 节点,还是 CSS 选择器来的方便好使不是么?

示例代码

本系列的所有代码小编都会放在代码管理仓库 Github 和 Gitee 上,方便大家取用。

示例代码-Github

示例代码-Gitee

参考

https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/#

小白学 Python 爬虫(22):解析库 Beautiful Soup(下)的更多相关文章

  1. python爬虫之解析库Beautiful Soup

    为何要用Beautiful Soup Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式, 是一个 ...

  2. 小白学 Python 爬虫(21):解析库 Beautiful Soup(上)

    小白学 Python 爬虫(21):解析库 Beautiful Soup(上) 人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前 ...

  3. 小白学 Python 爬虫(23):解析库 pyquery 入门

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  4. 小白学 Python 爬虫(32):异步请求库 AIOHTTP 基础入门

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  5. 小白学 Python 爬虫(25):爬取股票信息

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  6. 小白学 Python 爬虫(26):为啥上海二手房你都买不起

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  7. 小白学 Python 爬虫(29):Selenium 获取某大型电商网站商品信息

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  8. 小白学 Python 爬虫(30):代理基础

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  9. 小白学 Python 爬虫(31):自己构建一个简单的代理池

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

随机推荐

  1. vim可视化模式

    进入:v 移动光标选中 c剪切.y复制(自动退出v模式,进入插入模式) p粘贴

  2. 函数式接口的使用 (Function、Predicate、Supplier、Consumer)

    参考:https://blog.csdn.net/jmj18756235518/article/details/81490966 函数式接口 定义:有且只有一个抽象方法的接口 Function< ...

  3. mysql的属性zerofill

    一.字段中zerofill属性的类似定义方式 SQL语句:字段名 int(M) zerofill 二.zerofill属性的作用 1.插入数据时,当该字段的值的长度小于定义的长度时,会在该值的前面补上 ...

  4. [Part 3] 在Ubuntu 16.04源码编译PCL 1.8.1支持VTK和QT

    本文首发于个人博客https://kezunlin.me/post/137aa5fc/,欢迎阅读! Part-3: Install and Configure PCL 1.8.1 with vtk q ...

  5. 老男孩python 自学day09 函数开始

    什么是函数? 函数用关键字def定义 语法: def 函数名(形参): 函数体 return 调用 函数名(实参) 命名规则:和变量一样 1. 由数字, 字母, 下划线组成 2. 不能数字开头. 更不 ...

  6. python的匿名函数

    在Python,有两种函数,一种是def定义,一种是lambda函数. lambda函数是Python一种生成函数对象的表达式形式.匿名函数通常是创建了可以被调用的函数,它返回了函数,而并没有将这个函 ...

  7. 抖音抖一抖-SVG和CSS视觉故障艺术小赏

    故障艺术,英文名称叫glitch,在很多赛博朋克作品中经常看到,其实就是故意表现一种显示设备的小故障效果,抖音的图标其实就是这种的效果,我们看下这个图标 这个图标中的红色和蓝色的偏移其实就是一种故障艺 ...

  8. 算法上机题目mergesort,priority queue,Quicksort,divide and conquer

    1.Implement exercise 2.3-7. 2. Implement priority queue. 3. Implement Quicksort and answer the follo ...

  9. pringBoot-MongoDB 索引冲突分析及解决【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  10. 华为云MVP:来自工业制造领域的微服务与云平台实践

    [摘要] 首先,和大家先聊聊的是为什么微服务.DevOps和云计算会在各个产业大行其道;其次,再谈谈微服务架构设计有那些自己独特的设计思想,和传统的SOA有什么区别;最后,我们再一起看一看在工业领域云 ...