Python爬虫-BeautifulSoup
“美丽汤”的爱恨
前边说偏爱xpath,在于操作简单,解析速度较快。但不可否认:BeautifulSoup比xpath稳定。但凡网页的标签顺序发生变化(增删改),基于xpath规则的提取方式极大可能就此失效,这样一来不得不“右键检查元素”,周而复始的修改xpath规则。而“美丽汤”提供了多种寻找标签方法,以图使用者达到最佳“确定标签”的目的,尽最大努力在网页发生改变的同时,旧代码仍然畅通无阻的运行。
可是成也萧何败萧何,考虑太多,“美丽汤”不得不显得“臃肿”,成为三个中解析速度中的最慢。然而比起令人生畏的正则,许多人也只好认了:“慢就慢吧”。
《Python网络数据采集》书中提到,BeautifulSoup一名源于《爱丽丝梦游仙境》里的同名诗歌。就突然好想去看,我说有空的话。
使用
关于环境安装的帖子网络上很容易找到,这里不提。
导包:from bs4 import BeautifulSoup
指定解析方式:soup = BeautifulSoup(response.text, "lxml")
或者页面写入本地,打开本地文件解析:soup = BeautifulSoup(open("xxxx"), "lxml")
爱丽丝文档示例
在一定的操作中以此范例文档试验(这是一个标签部分残缺的文档)
格式化输出:print(soup.prettify())
效果:
可以看到,经过处理后,原示例的残缺部分被填充完整。所以我们应该针对处理之后的示例采取相应的提取措施
标签
soup.a
返回第一个a标签
soup.parent
返回a标签的父标签
soup.a.parent.name
返回a标签的父亲标签的名字
soup.a.parents
返回a标签的父级以上标签,类型为迭代器
对应parents的是children,用法相同,返回子级标签,注意区别,parents是父级以上,children只有子级
soup.a.attrs
返回a标签中的所有属性
soup.a.attrs["属性名"]
返回a标签指定属性对应的值
soup.title.string
返回title标签中的文本信息
soup.head.string
返回head标签中的文本信息
可以看到,返回结果相同,此方法也能返回注释信息
与字符串存在类型区别,但我认为没必要在入门的时候区分这些,以后需要的时候再研究就可以了
遍历
下行遍历:
.contents
返回一个列表
.children
返回一个迭代器
.descendants
返回子孙级标签,上面两个只有子级
上行遍历:
.parents
平行遍历:
.next_sibling
下一个平行标签
.previous_sibling
上一个平行标签
.next_siblings
后面所有平行标签,返回类型为迭代器
.previous_siblings
前面所有平行标签,返回类型为迭代器
find(),findAll()
find(tag, attrs, recursive, text, keywords)
findAll(tag, attrs, recursive, text, limit, keywords)
区别:除了参数limit外,前者返回第一个符合条件的对象,后者以列表方式返回所有符合条件
——针对tag参数——–
-findAll("a")
寻找所有a标签
-findAll({"a", "b", "p"})
寻找所有a,b,p标签
——针对attrs参数——-
+findAll("a", {"class":"sister"})
寻找标签a且属性class=”sister”
+findAll("a", {"class":{"sister", "brother"})
寻找标签a且属性class=”sister”或者brother
+findAll("", {"class":"sister"})
不限定标签类型,返回符合属性条件的标签
+以上可以看出,attrs属性不能单独使用
——针对text参数——–
-findAll(text="test")
区配文本内容为test的标签,返回该内容的列表
——-针对keyword参数——–
+findAll(id="link1")
寻找属性id=”link1”的标签
+findAll(class_="sister")
寻找属性class=”sister”的标签,由于class是python的关键字,所以为了避免冲突,需要加”_”符号
但可以用前面方法替代:soup.findAll("", {"class":"sister"})
—–针对参数recursive——
-默认True,当等于False的时候,只查询文档的一级标签
—–针对参数limit——
+find()就是findAll()的limit参数等于1的时候
get_text(),清除标签,即获取标签里的文本信息
综合使用
上述三类方法是可以综合使用的,比如如果我想在爱丽丝文档中寻找id=”link1”的标签可以这样写:soup.findAll("p",{"class":"title"})[0].next_sibling.next_sibling.findAll(id="link1")
支持正则
由于正则可以讲的地方太多,有空再特别写一篇关于正则的总结吧
CSS选择器
同样基于爱丽丝文档
select("title")
选择title标签,返回列表
select(".sister")
选择class=”sister”的标签,返回列表
select("#link1")
选择id=”link1”的标签,返回列表
select("head > title")
选择head标签下的title标签,符号”>”左右两边一定要有空格
select("p #link2")
选择p标签下符合id=link2的标签
soup.select('a[id="link3"]')
选择a标签中id=link3的标签