使用BeautifulSoup包解析源代码
- 前导:BeautifulSoup自动将输入文档转换为Unicode便阿门,输出文档转换为utf-8编码
- 解析方式(需要借助第三方库lxml) BeautifulSoup(markup,“lxml”) markup为获得的源代码,解析后产生一个类似于文档树的东西
1. 导入包
import requests
from bs4 import BeautifulSoup
2.获取网页
r = requests.get(url = "https://www.csdn.net/") #获取网页信息
print(r)
print(r.text) #输出网页源代码
3.进行解析
- 发现内容和r.text相同,但是类型已经变成BeautifulSoup的树状类型
soup = BeautifulSoup(r.text,'lxml')
print(soup) #发现内容类似r.text
print('*****************')
print(type(soup)) #发现类型不再是r.text的str,而是一种bs4的树状类型
4. 格式化输出(使用.prettify()方法)
- 按照html的缩进方式输出结果
print(soup.prettify())
5. 提取html的标签 Tag
- 使用以下方法只返回第一个标签内容
print(soup.title) #标题标签
print('***************************')
print(soup.head) #头部信息
print('***************************')
print(soup.body) #正文内容
print('***************************')
print(soup.a) #链接标签
6. 对于标签的属性(用.name和.attrs)
- 对于Tag,有两个属性:name(标签名称)和attrs(标签属性)
- soup.name 较为特殊,它的name即为[document]
print(soup.title.name)
print(soup.div.name)
print(type(soup.div.name)) #以str形式返回
print(soup.name) #较为特殊,树的顶层
print(soup.title.attrs)
print(soup.a.attrs)
print(soup.p.attrs)
print(type(soup.a.attrs)) #以字典形式返回
"""利用它的字典形式获取属性内容"""
print(soup.p.attrs['class'])
7. 提取html的标签元素文字(使用.string) NavigableString
- 类型是一个NavigableString,可以遍历的字符串
注意:.string只能用于单个标签,无法用于嵌套类型的标签
print(soup.title.string)
print(soup.a.string)
print(soup.p.string)
print(type(soup.title.string)) #
-
使用.string和.text方法的区别
- string获取内容是可遍历字符串形式
- text获取内容只是文本str形式
- text可以显示嵌套标签内容,而string只能显示独立标签内容
- text显示没有元素的标签区块时空着
print(soup.title.string)
print(soup.title.text)
print(type(soup.title.string)) #string获取内容是可遍历字符串形式
print(type(soup.title.text)) #text获取内容只是文本str形式
print(soup.head.string) #string只能显示独立标签内容
print(soup.head.text) #text可以显示嵌套标签内容 #没有元素的标签区块空着
8. 直接子节点(使用.contents,.children)
所有子孙节点用(.descendants)
- .contents返回列表,.children返回一个生成器
print(soup.head.contents) #打印列表形式的内容
print(type(soup.head.contents)) #以一个列表返回
print('**********************')
print(type(soup.head.children)) #以一个生成器返回
for i in soup.head.children: #打印生成器内容
print(i)
- 打印所有子孙节点用.descendants , 返回的也是一个生成器
print(type(soup.head.descendants))
for i in soup.head.descendants:
print(i)
9. 父节点(只要一个父节点使用.parent,所有父节点用.parents)
- .parent 返回的是一个节点结构
- .parents返回的是一个生成器,每一个生成器结果都是一个节点结构
""".parent"""
print(type(soup.title.parent)) #只取一个父节点,是节点类型
print(soup.title.parent) #直接打印上一节点所有内容
""".parents"""
print(type(soup.title.parents)) #取所有父节点,返回一个生成器,每一个生成器产生结果都是一个节点
for i in soup.title.parents: #打印生成器内容
print(i)
- 打印所有父节点标签名
- 打印到document说明上面已经没有父节点了
"""打印所有父节点标签名"""
for i in soup.title.parents:
print(i.name) #打印到document说明上面已经没有父节点了
10.兄弟节点(.next_sibling和.previous_sibling 与 .next_siblings和.previous_siblings)
- 理解为同一层次的节点
- .next_sibling返回下一个兄弟节点, .previous_sibling返回上一个兄弟节点
- .next_siblings返回下面所有兄弟节点组成的生成器, .previous_siblings返回上面所有兄弟节点组成的生成器
print(soup.title.next_sibling)
print(soup.title.next_sibling.previous_sibling) #返回到下面又返回上去到自己
print(type(soup.p.next_sibling))
print(type(soup.p.next_sibling))
for i in soup.title.next_siblings: #输出下面所有兄弟节点组成的生成器
print(i)
print('*********************')
for i in soup.title.previous_siblings: #输出上面所有兄弟节点组成的生成器
print(i)
11.前后节点(.next_element和.previous_element 与 .next_elements和.previous_elements
- 与兄弟节点不同,并不是针对兄弟节点,而是在所有节点上不分层次的获取前后节点
- .next_element和.previous_element返回一个节点
- .next_elements和.previous_elements返回一个节点生成器
print(type(soup.div.next_element))
print(soup.div.next_element)
print(soup.div.previous_element)
for i in soup.div.next_elements: #用生成器打印所有后节点
print(i)
print('******************************')
for i in soup.div.previous_elements: #用生成器打印所有前节点
print(i)
重点12. find_all()
- 搜索当前tag所有子节点,并判断是否符合过滤的条件
- find_all(name,attrs,recursive,string,**kwargs)
其中’name’为标签名称,'attrs’为标签属性
print(soup.find_all('title')) #按标签查找 返回所有'title'内容
print(soup.find_all('meta')) #按标签查找 返回所有'meta'内容
print(type(soup.find_all('title'))) #返回的是一种bs4的列表形式
- 使用name和attrs控制搜索范围
print(soup.find_all('img',"pre-img-lasy")) #按名称与属性内容查找,一般不用,而是选择keyword参数
- 使用limit参数控制搜索量
print(soup.find_all('img',limit = 2)) #控制搜索量为2
- keyword参数 比较重要
- 通过属性的关键字来查找 属性 = ‘内容’ 表示查找属性为’ '的标签内容
- 通过含有某一属性的来查找 属性 = True 表示查找所有包含这一属性的标签内容
- 通过正则re包来爬取特定内容
"""通过属性的关键字来查找"""
soup.find_all('meta',content="IE=Edge") #其中content="IE=Edge"为属性内容关键字
"""查找所有含某一属性的来查找"""
soup.find_all('meta',content = True) #查找所有含content属性的标签内容
- 通过正则re来作为关键字加compile查找
import re #导入re正则包
print(soup.find_all('a',limit = 5))
print('*******************************************')
print(soup.find_all('a',href = re.compile("/nav/engin"))) #查找属性中含关键词"/nav/engin"的内容
for i in soup.find_all('a',href = re.compile('/nav/')):#输出生成器
print(i.attrs['href']) #打印所有属性为href的内容
print('*******************************************')
for i in soup.find_all('a',href = re.compile('/nav/')):#输出生成器
print(i.string) #打印所有查询到的元素(bs4内部一种结构)
print('*******************************************')
for i in soup.find_all('a',href = re.compile('/nav/')):#输出生成器
print(i.text)
( 可以用find_all()中limit=1代替 )
print(soup.find('a'))
- find()语句的嵌套
print(soup.find('div').find_all('li',limit = 2)) #使用find与find_all进行嵌套寻找
本文章所附带的Jupyter notebook文件中含有完整代码以及详细案例