爬虫 >>> BeautifulSoup 模块
简称BS4;是一个可以从 HTML 或 XML 文件中提取数据的 python 库。
中文文档
# 官网推荐使用。因为效率更高(速度快, 文档容错能力强) # 容错处理,文档的容错能力指的是在 html 代码不完整的情况下,使用该模块可以识别该错误 # 并能按照标准的缩进格式的结构输出 pip3 install lxml
基本使用
遍历文档树
直接通过标签名字选择:速度快,存在多个相同的标签则只返回第一个
from bs4 import BeautifulSoup soup = BeautifulSoup('要解析的内容', '解析器(一般使用"lxml")') # 1:美化作用(帮助我们处理好缩进,结构化显示) soup = soup.prettufy() # 2:获取标签 soup.p # ---> soup 内的 p 标签;存在多个相同的标签则只返回第一个 soup.a # ---> soup 内的 a 标签;存在多个相同的标签则只返回第一个 # 2:获取标签名称 soup.p.name # ---> 结果为 p # 3:获取标签内的属性 soup.p.attrs # ---> p 标签内有多少属性都会以字典的形式返回(包括自定义属性) # 4:获取标签内容 soup.p.string # ---> p 标签下面文本只有一个时候可以取到,否则为 None soup.p.strings # ---> 拿到一个生成器对象 generater, 取到 p 下的而所有文本内容 soup.p.text # ---> 取到 p 下所有的文本内容 for line in soup.stripped_strings: # 去掉空白 print(line) # 5:嵌套选择 soup.head.title.string # ---> head 标签下 title 标签内的内容 # 6:子节点、子孙节点 soup.p.contents # ---> p 下所有子节点 soup.p.children # ---> 得到一个迭代器,包含 p 下面所有的子节点 soup.p.descendants # ---> 获取子孙节点,p 下所有的标签都会被选择出来 # 7:父节点、祖父节点 soup.a.parent # 获取 a 标签的父节点 soup.a.parents # 找到 a 标签所有的祖父节点,父亲的父亲... # 8:兄弟节点 soup.a.next_sibling # 下一个兄弟 soup.a.next_siblings # 下面的兄弟们(生成器对象) soup.a.previous_sibling # 上一个兄弟 soup.a.previous_siblings # 上面的兄弟们(生成器对象)
搜索文档树
# find 与 find_all ''' 区别是 find_all() 方法的返回结果是值包含一个元素的列表 而 find() 方法直接返回结果 find_all() 方法没有找到目标是返回空列表 find() 方法找不到目标时,返回 None ''' from bs4 import BeautifulSoup soup = BeautifulSoup('文档内容', 'lxml') # 1:五中过滤器 ---> 字符串、正则表达式、列表、布尔值、方法 # 1.1:字符串(字符串代表标签名) soup.find_all('b') # 搜索所有的 b 标签 # 1.2:正则表达式 import re soup.find_all(re.compile('^b')) # 找出所有 b 开头的标签;如 body, b 标签 # 1.3:列表 soup.find_all(['a', 'b']) # 与列表中任一元素匹配的内容返回 # 1.4:布尔值 soup.find_all(True) # 可以匹配任何值,查找到所有的tag, 但是不会返回字符串节点 # 1.5:方法 # 先定义一个方法:方法只接受一个元素参数。 # 如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False def has_class_but_no_id(tag): return tag.has_attr('class') and not tag.has_attr('id') soup.find_all(has_class_but_no_id) # 传入方法名 # 2、find_all( name , attrs , recursive , text , **kwargs ) # 2.1、name: 搜索name参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True . print(soup.find_all(name=re.compile('^t'))) # 2.2、keyword: key=value的形式,value可以是过滤器:字符串 , 正则表达式 , 列表, True . print(soup.find_all(id=re.compile('my'))) print(soup.find_all(href=re.compile('lacie'), id=re.compile('\d'))) # 注意类要用class_ print(soup.find_all(id=True)) # 查找有id属性的标签 # 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性: data_soup = BeautifulSoup('<div data-foo="value">foo!</div>', 'lxml') # data_soup.find_all(data-foo="value") #报错:SyntaxError: keyword can't be an expression # 但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag: print(data_soup.find_all(attrs={"data-foo": "value"})) # [<div data-foo="value">foo!</div>] # 2.3、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一 print(soup.find_all('a', class_='sister')) # 查找类为sister的a标签 print(soup.find_all('a', class_='sister ssss')) # 查找类为sister和sss的a标签,顺序错误也匹配不成功 print(soup.find_all(class_=re.compile('^sis'))) # 查找类为sister的所有标签 # 2.4、attrs print(soup.find_all('p', attrs={'class': 'story'})) # 2.5、text: 值可以是:字符,列表,True,正则 print(soup.find_all(text='Elsie')) print(soup.find_all('a', text='Elsie')) # 2.6、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.
# 效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果 print(soup.find_all('a', limit=2)) # 2.7、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点
# 如果 只想搜索tag的直接子节点,可以使用参数 recursive=False . print(soup.html.find_all('a')) print(soup.html.find_all('a', recursive=False)) ''' 像调用 find_all() 一样调用tag find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法.
BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同,下面两行代码是等价的: soup.find_all("a") soup("a") 这两行代码也是等价的: soup.title.find_all(text=True) soup.title(text=True) ''' # 3:CSS选择器 from bs4 import BeautifulSoup soup = BeautifulSoup('dfjeisdf,'lxml') # 3.1、选择标签 print(soup.p.select('.sister')) print(soup.select('.sister span')) print(soup.select('#link1')) print(soup.select('#link1 span')) print(soup.select('#list-2 .element.xxx')) print(soup.select('#list-2')[0].select('.element')) # 可以一直select,但其实没必要,一条select就可以了 # 3.2、获取属性 print(soup.select('#list-2 h1')[0].attrs) # 3.3、获取内容 print(soup.select('#list-2 h1')[0].get_text())
总结
# 1、推荐使用lxml解析库 # 2、三种选择器:标签选择器,find与find_all,css选择器 ''' 1、标签选择器筛选功能弱,但是速度快 2、建议使用 find, find_all 查询匹配单个结果或者多个结果 3、如果对 css 选择器非常熟悉建议使用 select ''' # 3、记住常用的 获取属性 attrs 和 文本值 get_text() 的方法