1. BeautifulSoup入门
from bs4 import BeautifulSoup
with open('index.html','r',encoding='UTF-8') as h:
soup = BeautifulSoup(h)
print(soup.prettify())
首先我自己做的时候有两个错误,第一个创建beautifulsoup对象的时候传入的不应该是那种url的链接,第二读取本地文件的时候会出现类似于gbk’ codec can’t decode byte 0x80 in position 90: illegal multibyte这种错误,这时候读文件的时候加上encoding就好啦
输出的结果是格式化了的网页代码
2.BeautifulSoup类的基本元素
将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归为:Tag,NavigableString,Comment**
Tag
①Tag就是最基本的标签,以<>开始
from bs4 import BeautifulSoup
# from bs4.diagnose import diagnose
with open('index.html','r',encoding='UTF-8') as h:
# diagnose(h)
soup = BeautifulSoup(h)
# fixed_html = soup.prettify()
print(soup.title)
我按照这种方式打印title的时候,弹出来一个警告,说是我现在没有定义解析器,然后系统默认用lxml来解析。搜了一下,我们可以用我上面注释掉的那句diagnose(h)来看看系统带的解析器有哪些。后续我都用了html.parser来解析。
此外还有print(soup.a.parent.name)
这样类似的形式可以打印出a的父标签的名字。
②Tag的两个属性:name attributes
name也就是标签的名字,直接print(soup.li.name)
就可以打印出来
attributes 就是这个标签含有哪些属性 print(soup.p.attrs)
打印出来的是字典形式的,也可以用例如print(soup.p.attrs['name'])
打印其中某项属性的值。等价操作
print(soup.p.get('name'))
print(soup.p['name'])
当然你也可以想到可以修改里面的属性和值
soup.p['name'] = 'dro'
del soup.p['name']
NavigableString
标签内的非属性字符串<>…
print(soup.p.string)
print(type(soup.p.string))
可以看一下它的类型就是NavigableString
Comment
标签内字符串的注释部分如果直接用.string方法打印它会自动去掉两边的注释,这可能会给我们带来不必要的麻烦。
我们找一个带有注释的,比如说下面这个:
<b><!--This is a comment--></b>
<p>This is not a comment</p>
比如,我们用soup.b.string
,输出的是this is a comment
type(soup.b.string),可以看出类型是bs4.element.Comment
下次我们就可以先判断类型再做下一步的操作啦 !
一个总结的图片:
3.基于bs4的HTML遍历方法
分为上行遍历、下行遍历和平行遍历
下行遍历
.contents 以列表的方式输出tag的子节点
print(soup.head.contents)
输出结果
[<title>The Dormouse's story</title>]
我们也可以用列表索引来获取它的某一项。
.children 子节点的迭代类型,用于循环遍历儿子节点
for child in soup.body.children:
print(child)
.descendants 子孙节点的迭代类型,
for child in soup.descendants:
print(child)
上行遍历
.parent
节点的父类标签
print(soup.p.parent.name)
.parents
节点先辈标签的迭代类型
for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)
结果:
p
body
html
[document]
平行遍历
.next_sibling 返回按照html顺序的下一个平行节点标签
.prev_sibling返回按照html顺序的上一个平行节点标签
实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行
print(soup.p.next_sibling.next_sibling)
.next_siblings 迭代类型
.prev_siblings 迭代类型
for sibling in soup.p.next_siblings:
print(sibling)
基于bs4库的格式化和编码
import requests
from bs4 import BeautifulSoup
req = requests.get("http://python123.io/ws/demo.html")
print(req.text)
demo = req.text
soup = BeautifulSoup(demo,'html.parser')
print(soup.prettify())
基于bs4库的HTML内容查找方法
find_all(name,attrs,recursive,string,**kwargs)
name:
①可以传入字符串。如果给定的值是True则会打印全部内容
print(soup.find_all('a'))
for tag in soup.find_all(True):
print(tag.name)
输出结果:
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
html
head
title
body
p
b
p
a
a
②可传入正则表达式
for tag in soup.find_all(re.compile('^b')):
print(tag.name)
要在最前面import re,可以匹配出所有含有a的标签
③可以传入一个list列表
print(soup.find_all(['a','b']))
结果如下:
[<b>The demo python introduces several python courses.</b>, <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
④可以传入一个函数
我还没实现。!!!!
attrs
attrs查找包含该属性的标签
print(soup.find_all('p','course'))
或者
print(soup.find_all('p',class_ = 'course'))
都能查找p标签里class为course的。
print(soup.find_all(id = 'link1'))
查找以link开头的id的标签:
print(soup.find_all(id = re.compile('^link')))
结果:
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
recursive
是否对子孙全部检索,默认是True
查找的其他方法: