bs4

bs4

BS4全称是Beatiful Soup,它提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为tiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编一下原始编码方式就可以了。

所以,它能处理html、xml,可以提取,也可以修改。

一种简单的常见的爬虫策略,requests + bs4,前者完成http请求下载,后者能完成html的解析。另外,用re库也能完成网页解析。

资源

官方文档

安装

pip install beautifulsoup4

建议使用 -i参数,指定国内的镜像源。

相关的解析器

  • 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格式的文档
    速度慢
    不依赖外部扩展

使用

最常用的还是BeautifulSoup对象和Tag对象,解析主要靠Tag对象,所以需要掌握bs4.element.Tag 的系列方法

对象

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳以下4种:

  • Tag对象:是html中的一个标签,用BeautifulSoup就能解析出来Tag的具体内容,与XML或HTML原生文档中的tag相同。
  • BeautifulSoup对象:整个html文本对象,可当作Tag对象
  • NavigableString对象:标签内的文本对象
  • Comment对象:是一个特殊的NavigableString对象,如果html标签内存在注释,那么它可以过滤掉注释符号保留注释文本

参数,第一个参数为html文本。选择解析器features="lxml"或者默认features="html.parser"。返回的对象。

from bs4 import BeautifulSoup

res = requests.get(链接)
# 使用默认的解析器
# soup = BeautifulSoup(res.text, features="html.parser")
# 或者
# 需要pip install lxml
soup = BeautifulSoup(res.text,"lxml")
soup = BeautifulSoup(res.text, features="lxml")
for ul in soup.find_all(name='ul'):
    for li in ul.find_all(name='li'):

查找三板斧

说句实话,我比较钟爱select方法,灵活、而且基本上不会增加额外的学习成本。

  • select

注意返回的是列表,不能直接get(‘属性名’)**。如果只有一个元素,也要用[0]来取**。也可遍历

soup.select("div.content h4 a")
soup.select("div.content h4 a")[0]
soup.select("div.content h4 a").select("")
soup.select("div.content h4 a").find("")
  • find

    快捷方式 tag.find(‘a’) => tag.a 无法带搜索条件。

这个返回的是一个元素。

soup.find(name="div",class_='content').find()
soup.find(name="div",class_=re.complie(r'\d+')).find()
# 如果不需要参数,只通过 name就能找到,可以简写
soup.find(name="div",class_='content').a
  • find_all

    快捷方式 tag.find_all(‘a’) => tag(‘a’)

    加上limit=1 find_all 等价于 find。 如 tag.find_all(‘a’,limit=1)

注意返回的是一个列表。也可遍历

soup.find(name="div",class_='content')

参数说明:

find、find_all的参数如下,对与参数,主要有tag或属性来搜索。

而利用tag.name或tag.attrs属性来进行过滤,(即过滤器)属性的取值可以有:

  • 字符串,完全匹配
  • 正则表达式,按正则的方式来匹配
  • 列表,匹配多个。
  • True,只要有就行。
  • 方法, 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
参数 名称 示例
name html节点名称,如div、h3、a、article等 div
id 节点的id id=”main-btn”
class_ 节点的类。估计是为了防止跟关键字重名 字符串或正则
text 文本内容。但是需要将结果转换str 字符串或正则
limit 限制返回数量。 2
recursive tag_all方法时,控制是否要遍历子孙节点。

补充示例:

movieCommentNum = str(detail.find(text=re.compile('\d+人评价')))
movieName = detail.find('span', class_='title').get_text()

# 根据内容来匹配

# 找到标签内的文本为story的文本内容
print(soup.find_all(text='story'))
# 找到标签内的文本含有story的文本内容
print(soup.find_all(text=re.compile(r'.*?story.*?')))

由于结果多数都是bs4.element.Tag或者 bs4.element.Tag数组。主要参考下面

取值

即掌握下面的内容

bs4.element.Tag

soup = BeautifulSoup(...)
soup.b  返回第一个标签
  • 获取Tag的name
tag.name
# 修改
tag.name = "p"
  • Tag的Attributes属性
# 获取单个属性 ,注意返回 list
tag['class']   # ['active']
# 获取所有属性
tag.attrs   # {'class': ['active']}

# 像字典那样操作
tag.get('class')

# 添加属性
tag['class'] = 'inactive'
tag['class'] = ['inactive','content']  # 注意,赋值多个class 属性
tag['id'] = 10
# 删除属性
del tag['id']
  • 文本内容

string得到标签下的文本内容,只有在此标签下没有子标签,或者只有一个子标签的情况下才能返回其中的内容,否则返回的是None;

get_text()可以获得一个标签中的所有文本内容,包括子孙节点的内容,这是最常用的方法

print(soup.a.string)    # 标签里面的内容
print(soup.a.get_text())

html

# 能返回html,也能修复缺失的内容
soup.prettify()

可遍历

获取html的内容

li_list = ul.find_all('li')
    for li in li_list:
       print(type(li))
       html = li.prettify()
       print(type(html))
       print(html)

其他方法

find_parents()和find_parent(): 前者返回所有祖先节点 后者返回直接父节点

find_next_sibings()和find_next_sibling(): 前者返回所有兄弟节点 后者返回后面第一个兄弟节点

find_previous_siblings()和find_previous_siblings(): 前者返回前面所有的兄弟节点 后者返回前面第一个兄弟节点

find_all_next() 和 find_next() 对.next_elements属性进行迭代

find_all_previous() 和 find_previous()