爬虫之Beautiful Soup(初学)

Beautiful Soup

简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。百度定义如下:
Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。
Beautiful Soup 安装
现在的项目中使用Beautiful Soup 4,不过它已经被移植到BS4了,也就是说导入时我们需要 import bs4 。所以这里我们用的版本是 Beautiful Soup 4.3.2 (简称BS4)
可以利用 pip 或者 easy_install 来安装,以下两种方法均可

easy_install beautifulsoup4

pip install beautifulsoup4
运行下面的命令即可完成安装
sudo python setup.py install

然后需要安装 lxml
pip install lxml
遍历文档树
(1)直接子节点
要点:.contents .children 属性
tag 的 .content 属性可以将tag的子节点以列表的方式输出
输出方式为列表,我们可以用列表索引来获取它的某一个元素
它返回的不是一个 list,不过我们可以通过遍历获取所有子节点。
我们打印输出 .children 看一下,可以发现它是一个 list 生成器对象
我们怎样获得里面的内容呢?很简单,遍历一下就好了。
(2)所有子孙节点
知识点:.descendants 属性
.descendants
.contents 和 .children 属性仅包含tag的直接子节点,.descendants 属性可以对所有tag的子孙节点进行递归循环,和 children类似,我们也需要遍历获取其中的内容。
for child in soup.descendants:
print child
运行结果如下,可以发现,所有的节点都被打印出来了,先生最外层的 HTML标签,其次从 head 标签一个个剥离,以此类推。
(3)节点内容
知识点:.string 属性
如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。
通俗点说就是:如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容。
如果tag包含了多个子节点,tag就无法确定,string 方法应该调用哪个子节点的内容, .string 的输出结果是 None
(4)多个内容
知识点: .strings .stripped_strings 属性
获取多个内容,不过需要遍历获取
输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容
(5)父节点
知识点: .parent 属性
(6)全部父节点
知识点:.parents 属性
通过元素的 .parents 属性可以递归得到元素的所有父辈节点
(7)兄弟节点
知识点:.next_sibling .previous_sibling 属性
兄弟节点可以理解为和本节点处在统一级的节点,.next_sibling 属性获取了该节点的下一个兄弟节点,.previous_sibling 则与之相反,如果节点不存在,则返回 None
注意:实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行
None 没有前一个兄弟节点,返回 None
下一个节点的下一个兄弟节点是我们可以看到的节点
(8)全部兄弟节点
知识点:.next_siblings .previous_siblings 属性
通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出
(9)前后节点
知识点:.next_element .previous_element 属性
与 .next_sibling .previous_sibling 不同,它并不是针对于兄弟节点,而是在所有节点,不分层次
比如 head 节点为The Dormouse’s story那么它的下一个节点便是 title,它是不分层次关系的
(10)所有前后节点
知识点:.next_elements .previous_elements 属性
通过 .next_elements 和 .previous_elements 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样
以上是遍历文档树的基本用法。
详细用法

'''
soup = BeautifulSoup(html_doc, 'html')
#features: fast, html, html.parser, html5, html5lib, lxml, lxml-html, lxml-xml, permissive, strict, xml
fast:一般不推荐使用,不同的系统选择不同的方式
'''
# soup = BeautifulSoup(html_doc, ['lxml', 'html5'])
# soup = BeautifulSoup(html_doc, ['html', 'html5'])
# soup = BeautifulSoup(html_doc, 'lxml')

'''不同builder的差异'''
# text = ''
# soup_test = BeautifulSoup(text, 'lxml') # 会补全 html,body和p
# print('lxml:')
# print(soup_test)
# soup_test = BeautifulSoup(text, 'html.parser') # 会补全 p
# print('html.parser:')
# print(soup_test)
# soup_test = BeautifulSoup(text, 'html5')  # 会补全 html,head,body和p
# print('html5:')
# print(soup_test)
# soup_test = BeautifulSoup(text, 'xml')  # 会加xml头,忽略错误的标签
# print('xml:')
# print(soup_test)


# print(soup.prettify())  # 直接输出文档,str类型,默认utf-8
# print(soup.prettify('gbk')) # 传入编码,输出 bytes
# print(soup.prettify('gbk').decode('gbk')) # 传入编码,输出 bytes

# print(soup.title) # 标签,包括标签本身
# print(soup.title.name) # 标签的名字
# s = soup.title.string
# print(soup.title.string) # 标签的内容, NavigableString 对象
# print(soup.title.text) # 标签的内容, str 对象

# print(soup.meta) # 标签
# print(soup.meta['charset']) # 标签属性

# print(soup.meta.parent.name) # 标签的父标签
# print(soup.html.parent.name)
# print(soup.html.parent.parent)

# text = '''
# text1text2
# text3<>
# '''
# sibling_soup = BeautifulSoup(text, 'lxml')
# print(sibling_soup.b.next_sibling) #  兄弟节点
# print(sibling_soup.c.previous_sibling) #  兄弟节点
# print(sibling_soup.c.next_sibling) #  兄弟节点,是 换行符
# print(sibling_soup.d.previous_sibling) #  兄弟节点,是 换行符

# print(sibling_soup.a.next_element) #  下一个元素,是 text1
# print(sibling_soup.b.next_element) #  下一个元素,是 text1
# print(sibling_soup.b.next_element.next_element) #  下一个元素,是 换行符
# print(sibling_soup.d.previous_element) #  上一个元素,是 换行符
# print(sibling_soup.f.previous_element) #  上一个元素,是 
# print('结束')

# print(soup.find_all('meta')) # 查找所有
# print(soup.find_all('meta', limit=2)) # 查找所有
# print(soup.find('meta', {'name': 'renderer'})) # 查找特定的一个标签,其实也是调用的find_all,不过会在取到一个值后返回
# print(soup.find(id="seajsnode")) # 根据id查找特定的一个标签

# print(soup.find(text='支付宝 知托付!')) # 根据标签内容查找特定的一个标签,不能仅仅有标签内容一个参数
# print(soup.find(text='支付宝 知托付!', test='test')) # 根据标签内容查找特定的一个标签,不能仅仅有标签内容一个参数
# print(soup.find('title', text='支付宝 知托付!')) # 根据标签内容查找特定的一个标签,不能仅仅有标签内容一个参数

# meta = soup.find('meta', {'name': 'renderer'})
# print(meta)
# print(meta.find_next_sibling('meta')) # 查找下个符合条件的兄弟节点
# print(meta.find_next_siblings('meta')) # 查找所有符合条件的兄弟节点
#
# print(meta.find_next_sibling('a')) # 查找下个符合条件的兄弟节点
# print(meta.find_next('a')) # 查找下个符合条件的节点
# print(meta.find_all_next('a')) # 查找所有符合条件的节点

# print(soup.find('body').get_text()) # 获取所有文本
# print(soup.find('body').get_text('|')) # 获取所有文本,| 是分隔符

'''
    标签对象一样可以使用所有方法
'''
# body = soup.find('body')
# print(body.find('div'))

'''
    标签对象,可以和字符串一样编码和解码
'''
# markup = "\N{SNOWMAN}"
# snowman_soup = BeautifulSoup(markup, 'html.parser')
# tag = snowman_soup.b
# print(tag)
# print(tag.encode("utf-8"))
# print(tag.encode("utf-8").decode('utf-8'))
# print(tag.encode("iso-8859-1"))
# print(tag.encode("iso-8859-1").decode('iso-8859-1'))
# print(tag.encode("gbk"))
# print(tag.encode("gbk").decode('gbk'))

'''
    css选择器
'''
# print(soup.select("title")) # 标签名
# print(soup.select("html head title")) # 逐层查找
# print(soup.select("body a")) # 不逐层查找

# print(soup.select("body > a")) # >  子节点
# print(len(soup.select("body > div"))) # >  子节点
# print(soup.select("body > div")) # >  子节点

# print(soup.select("input ~ p")) # >  兄弟节点

# print(soup.select("#test_id"))  # 通过id
# print(soup.select("input#test_id"))  # 通过id

# print(soup.select('.test_class')) # 通过class

# print(soup.select('meta[charset="gb2312"]'))

你可能感兴趣的:(爬虫之Beautiful Soup(初学))