python爬虫之bs4模块
June 1, 2018 Python学习 访问: 36 次
美化网页数据
bs4简介
即BeautifulSoup,是python种的一个库,最主要的内容就是从网页中抓取数据。
官方解释:
Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。
使用方法
首先我们要导入bs4库
from bs4 import BeautifulSoup
然后我们利用requests或者urllib2来打开一个网址(这里用http://www.qq.com为例子来展开描述的)
import requests
url = "http://www.qq.com"
r = requests.get(url,'lxml')
print r.content
创造一个BeautifulSoup对象
bs_1 = BeautifulSoup(r.text,'lxml')
然后通过这个对象来实现对拔下来的源码进行筛选和处理
print ba_1.prettify() #格式化输出全部内容
print bs_1.[标签名]
有html,head,title,meta,body,script,style等等
分别输出标签对之间的代码
BeautifulSoup四大对象种类
Beautiful Soup 将复杂HTML文档转换成一个复杂的树形结构,每个节点都是 Python 对象,所有对象可以归纳为4种:
- Tag
- NavigableString
- BeautifulSoup
- Comment
tag
通俗的来讲就是HTML中的一个个标签,如html,head,title,meta,body,script,style等等,不过有一点是,它查找的是在所有内容中的第一个符合要求的标签,并不是所有的
对于每个标签来说,都一个共性,那就是都含有两个属性:name和attrs,用法如下:
print bs_1.[标签名][name/attrs]
eg:
print bs_1.div.name <!--div-->
print bs_1.div.attrs <!--{'style': 'display:none;overflow:visible;', 'id': 'QQ_takeover', 'class': ['l_qq_com']}-->
把div的所有属性都打印出来,返回的是一个字典类型的,若想取其中的某一个指,则可用:
print bs_1.div['class'] <!--['l_qq_com']-->
NavigableString
主要作用是把标签内部中的文字提取出来,用法如下:
print bs_1.title #<title>腾讯首页</title>
print bs_1.title.string # 腾讯首页
假如一个标签中的内容是注释过的
<!DOCTYPE html>
<html>
<head>
<title>hahaha</title>
</head>
<body>
<a href="123456"><!--hahahahahah--></a>
</body>
</html>
那么:
print bs_1.a.string
返回的结果就是hahahahahah,并不输出注释符
BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容,和tag有点相似。
Comment
总的来说,Comment是一个特殊的NavigableString对象,当然也不输出注释符。
遍历文档树
标签的.contents可以将会标签的子节点以列表的方式输出
print bs_1.style.contents
输出结果:
[u'\r\n .leftVideoNews .ft{height:168px;overflow:hidden;}\r\n #jinrituhua{height:auto;}\r\n #jinrituhua .bd{padding:12px 0 17px;}\r\n #jinrituhua .ft{height:224px;overflow:hidden;}\r\n #jinrituhua li{width:330px;padding:0;background:none;} \r\n']
如果要取出列表中的某一个值的话,可以用索引来取出
print bs_1.style.contents[0]
结果:
.leftVideoNews
.ft{height:168px;overflow:hidden;}
#jinrituhua{height:auto;}
#jinrituhua .bd{padding:12px 0 17px;}
#jinrituhua .ft{height:224px;overflow:hidden;}
#jinrituhua li{width:330px;padding:0;background:none;}
标签的.children可以返回一个 list 生成器对象,而不是直接返回一个子节点
print bs_1.style.children
结果:
<listiterator object at 0x0000000006DB9A90>
获取这个之后,我们可以通过遍历获取所有子节点
for child in bs_1.style.children:
print child
结果:
.leftVideoNews .ft{height:168px;overflow:hidden;}
#jinrituhua{height:auto;}
#jinrituhua .bd{padding:12px 0 17px;}
#jinrituhua .ft{height:224px;overflow:hidden;}
#jinrituhua li{width:330px;padding:0;background:none;}
所有子孙节点---.descendants
.contents 和 .children 属性仅包含标签的直接子节点,.descendants 属性可以对所有tag的子孙节点进行递归循环,和 children类似,我们也需要遍历获取其中的内容。
for child in bs_1.descendants:
print child
从最大的标签对html开始,一层一层的开始列出所有的子节点
节点内容
单个内容
如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容
多个内容
同样也需要遍历
print bs_1.strings
结果:
<generator object _all_strings at 0x0000000005AF1EE8>
r = requests.get(url)
bs_1 = BeautifulSoup(r.text,'lxml')
for string in bs_1.strings:
print(repr(string))
若取出来的有多行是空白内容,可以使用stripped_strings
for string in bs_1.stripped_strings:
print(repr(string))
repr() 函数将对象转化为供解释器读取的形式。
父节点
单个父节点
.parent可以得到上一级的标签,通过标签可以访问上一级标签的name和attrs值
print bs_1.a.parent.name
结果:
div
多个父节点
.parents可以得到所有的父节点,要输出那就得遍历
bs_1 = BeautifulSoup(r.text,'lxml')
for parent in bs_1.title.parents:
print parent.name
结果:
head
html
[document]
兄弟节点(处在本级的节点)
.next_sibling可以获取到下一个的节点
print bs_1.p.next_sibling
.previous_sibling 可以获取到上一个的节点
print bs_1.p.previous_sibling
全部兄弟节点
.next_siblings 之后的兄弟节点
.previous_siblings 之前的兄弟节点
for sibling in bs_1.a.next_siblings:
print(repr(sibling))
单个前后节点
.next_element可以获取到临近它的下一个节点,而不分层次关系
.previous_element可以获取到临近它的上一个节点
print bs_1.meta.next.element
多有的前后节点
.next_elements 该节点前的所有节点
.previous_elements 该节点后的所有节点
for element in last_a_tag.next_elements:
print(repr(element))
从整个网站寻找
find_all(name,attrs,recursive,text,**kwargs)
naem
传字符串
print bs_1.find_all('a')
结果:
[<a class="qskinmouseover" href="http://v.qq.com/p/cross/20180524/Wlx2799t.html" id="qskinmouseover" target="_blank" title="">\n<img alt="\u516d\u4e00\u966a\u4f34\u65e5" src="//mat1.gtimg.com/www/qqskin/20180531_children.png"/>\n</a>, <a bosszone="logo" class="qqlogo" href="//www.qq.com" id="tencentlogo" target="_blank">\n<img alt="\u817e\u8baf\u7f51" src="//mat1.gtimg.com/www/qq2018/imgs/qq_logo_2018x2.png"/>\n</a>, <a href="https://www.sogou.com/?pid=sogou-wsse-3f7bcd0b3ea82268-0001" id="sogouLogoLink" onclick="registerZone2({bossZone:'searchlogo',url:''},1);" target="_blank"><img alt="\u641c\u72d7" class="sosoLogo" id="sogouLogo" src="//mat1.gtimg.com/www/images/qq2012/sogouSearchLogo20140629.png" style="width:23px;height:23px;"/></a>, <a bosszone="onekey" class="login" href="javascript:void(0)" id="loginGrayLayout" onclick="userLogin();" target="_self"></a>, <a bosszone="qmail" class="mail" href="http://mail.qq.com" target="_blank"></a>, <a bosszone="qzone" class="qzone" href="http://qzone.qq.com" target="_blank"></a>, <a bosszone="touxiang" class="logined" href="http://ilike.qq.com" id="loginGrayLayoutLogin" target="_blank">\n<img id="loginGrayLayoutImg" src=""/>\n</a>, <a bosszone="touxiang" class="userVipHead" href="http://ilike.qq.com" id="userVipHead" target="_blank"></a>]
传入正则表达式(使用re模块,这里不再详细列出)
传入列表
传入ture
传方法
等等
CSS选择器
css的规则:标签名不加任何修饰,类名前加点,id名前加#,在这里用的方法大致是一样的,用到的方法是bs_1.select(),它的返回值是一个列表list;
通过标签名字
print bs_1.select('title')
通过类名
print bs_1.select('.class')
通过id
print bs_1.select('#a_1')
组合查找
这个和在写css的格式是一样的
print bs_1.select('.class #id')
意思是查找.class类下的id是id的元素
子查询
print bs_1.select('head > title')
属性查找
print bs_1.select(p[class="new"])
总结
这里只是列出了部分的查找方法,还有很多的查找方法,详细请看官网。