python爬虫之BeautifulSoup的用法

标签: python  爬虫  bs4

概念:Beautiful Soup 是什么?

  • Beautiful Soup是一个可以从HTML或XML文件中提取数据的python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。
  • 目前Beautiful Soup3已经停止开发,推荐使用Beautiful Soup4

解析器

  • Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml
解析器 使用方法 优势 劣势
Python标准库 BeautifulSoup(markup, “html.parser”) Python的内置标准库 执行速度适中 文档容错能力强 Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
lxml HTML 解析器 BeautifulSoup(markup, “lxml”) 速度快 文档容错能力强 需要安装C语言库
lxml XML 解析器 BeautifulSoup(markup, [“lxml”, “xml”])BeautifulSoup(markup, “xml”) 速度快 唯一支持XML的解析器 需要安装C语言库
html5lib BeautifulSoup(markup, “html5lib”) 最好的容错性 以浏览器的方式解析文档 生成HTML5格式的文档 速度慢 不依赖外部扩展

对象的种类

Beautiful Soup将复杂的HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归纳为4种:tag , NavigableString , Beautfulsoup, Coment

  • tag : 简单的讲就是HTML中的一个个标签

  • NavigableString :tag中的字符串

  • BeautifulSoup :是一个文档的全部内容,大部分的时候,可以把他当做tag对象,是一个特殊的tag。因为BeautifulSoup对象并不是真正的HTML或XML的tag对象所有没有name和attribute属性,但有时查看它的.name属性是很方便的,所有BeautifulSoup对象包含了一个值为“[ducument]” 的特殊属性.name
  • Comment : 是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号

遍历文档树

(1)获取子节点
    .contents    列表形式
    .children    返回的是一个生成器,需要遍历查看
(2)获取所有子孙节点
     .descendants  对所有tag的子孙节点进行递归循环,和children类似
(3) 节点内容
    .string 
    如果一个标签里面没有标签了,那么.string 就会返回标签里面的内容。
    如果标签里面只有唯一的一个标签了,那么.string 也会返回最里面的内容。
    如果tag包含了多个子节点,tag就无法确定,string方法应该调
    用哪个子节点的内容,string的输出结果是None
(4)多个内容
    .strings 获取多个内容,不过需要遍历

find,find_all, select方法的使用

对于我们写爬虫基本上用的只有查找,大部分我们用的时候也就是这几个方法:find,find_all, select

find_all()讲解

find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
以下是find_all()方法以及参数的用法

find_all(self, name=None, attrs={}, recursive=True, text=None,
             limit=None, **kwargs)
  • name :
    可以查找所有名字为name的tag,字符串对象会被自动忽略掉。内容可以是(字符串,正则,列表,Ture)

       Ture可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点,还可以传一个方法:
       如果没有一个合适的过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果 这个方法返回True表示匹配成功,否者False
    
  • attrs :
    规定tag中的属性,传入的是一个字典

  • recursive :
    默认是True 查找当前tag下的所有子孙节点。如果设置False那么只查找tag的直接子节点

  • text :
    查找节点中的内容字符串,与name参数的可选值一样。这个可以用定向查找某一个节点,获取节点的属性

  • limit :
    限制符合搜索条件的个数,比如符合条件的有5个,但是我们设置2个那么就只返回符合条件的前两个。和sql中的limit类似。

  • kwarys :
    如果一个指定名字的参数不是find_all()函数内置的参数,搜索时会把该参数当做指定名字tag的属性来搜索

       形式可以是: id =‘link’或 id =re.compile()。但是有些特殊的tag属性是不可以使用的。比如h5中data-*。
       所以一般情况下都会在attrs中规定查找tag的属性。
    

看十遍不如动手做一遍,废话不多说直接实例着手。


实例

我把网页源代码放在了一个文件当中了

import sys
import codecs
from bs4 import BeautifulSoup

reload(sys)
sys.setdefaultencoding('utf-8')

data = codecs.open('2.html','r',encoding= 'utf-8').read()
#创建beautifulSoup 对象
soup = BeautifulSoup(data, 'lxml')

这里写图片描述

#获取每部小说链接
li = soup.find('div',class_='listBox').find('ul').find_all('li')
for i in li:
    url = i.find('a',recursive=False).get('href')
    print url
输出:
/36171.html
/36169.html
/36161.html
/36151.html
/36148.html

这里写图片描述

limit值的设定

#获取下面页数链接
dia = soup.find('div',class_='tspage').find_all('a',limit=1)
print dia
print type(dia)
for i in dia:
    print i.get_text()   #获取节点内容
    print i.get('href')   #获取节点某一属性

输出:

[<ahref="/soft/sort01/index_2.html">\u4e0b\u4e00\u9875</a>]
<class 'bs4.element.ResultSet'>
下一页
/soft/sort01/index_2.html

这里写图片描述

text的使用

一般知道节点内容,用来获取节点属性

# 知道节点内容,获取节点属性
di = soup.find('div',class_='wrap header')\
    .find('a',text=u'首页').get('class')
print di

输出:

['nav-cur']

这里写图片描述

recursive值的设定

# div ->  select ->option
option = soup.find('div',class_='tspage').find_all('option',limit=2)
for i in option:
    print i.text

option = soup.find('div',class_='tspage').find_all('option',limit=2,recursive=False)
print option
if option:
    for i in option:
        print i.text
else:
    print u'没有找到'

输出:

第 1 页
第 2 页
[]
没有找到

find() 用法和find_all()一样。

find(self, name=None, attrs={}, recursive=True, text=None,
         **kwargs)

select()方法

css选择器—-soup.select() ,返回类型是list

select(self, selector, _candidate_generator=None, limit=None)

查找方法:

(1)通过标签名查找        tag标签
(2)通过类名查找         .类名
(3)通过id名查找         #id
(4)组合查找(标签,类名,id组合查找,直接子标签查找)
(5)属性查找
(6)通过语言设置来查找
    soup.select('a[href]'
multilingual_soup.select('p[lang|=en]')

# [<p lang="en">Hello</p>,
#  <p lang="en-us">Howdy,y'all</p>,
#  <p lang="en-gb">Pip-pip, old fruit</p>]

我们在写css样式时,标签名不加任何修饰,类名前加点,id前加#,在这里我们可以利用类似的方法来筛选,通过tag标签逐层查找。

这里写图片描述

ul = soup.select(".listBox > ul > li > a")
for u in ul:
    print u.text

输出:

《我是大玩家》全集
《仙武至尊》全集
《从主播到主神》全集
《都市之重返人间》全集

总结

发现我们在使用Beautiful Soup时主要使用的也就是find,find_all(),select这三个方法。
写一下我用Beautiful Soup查找时的思路
(1)用find定位到要查找的节点的父节点位置。
(2)如果这个父节点下的所有子节点都是我们想要的,那么就用find_all查找,如果只有一个使我们想要的就用find查找
(3)查找到某个节点后,获得内容用.text或string或get_text(),获取节点属性用.get()或者"节点名['属性名']"

**参考文档
Beautiful Soup 4.2.0 文档:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id47

版权声明:本文为lowerxiaoshen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lowerxiaoshen/article/details/77461649