python爬虫笔记(四):BeautifulSoup

BeautifulSoup使用

Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python库. 它能够通过你喜欢的转换器实现惯用的文档导航, 查找, 修改文档的方式. Beautiful Soup会帮你节省数小时甚至数天的工作时间.
之后会整理一下XPath的用法,在使用scrapy框架进行爬虫时,需要用到。
Xpath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历,也算比较好理解的。

一、创建BeautifulSoup对象

构造函数参数比较多,主要介绍前两个参数:
第一个参数是 markup,默认为空字符串。A string or a file-like object representing markup to be parsed.
第二个参数是 features,Desirable features of the parser to be used. 即文本解析器
可指定特定解析器:”lxml”, “lxml-xml”(唯一支持xml解析),”html.parser”(python内置), or “html5lib”

import urllib.request
from bs4 import BeautifulSoup

douban_path = "https://movie.douban.com"
response = urllib.request.urlopen(douban_path)
soup = BeautifulSoup(response, 'html.parser')
# 可以接受response对象

soup = BeautifulSoup(response.read().decode('utf-8'), 'html.parser')
# 可以接受字符串

soup = BeautifulSoup(open(test.html),'html.parser')
# 可以接受本地文件

soup.prettify() :有层次结构的输出html文档(父子兄弟关系),和开发者模式看到的差不多
soup.get_text(): 获取所有文字信息 对单个节点来说和 .string 一样


二、bs4四大对象种类

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

  1. Tag
  2. NavigableString
  3. BeautifulSoup
  4. Comment
(1).Tag

Tag通俗点讲就是HTML中的一个个标签,例如:

<title>_zhaowendao_</title>

得到 BeautifulSoup 对象后直接以属性形式输出, 但它查找的是在所有内容中的第一个符合要求的标签

print(soup.title)
# <title>
#        豆瓣电影
#</title>

print(soup.a)
# <a class="nav-login" href="https://www.douban.com/accounts/login?source=movie" rel="nofollow">登录</a>

对于Tag,有两个重要的属性:name和attrs

name:标签本身的名字,如标题h1, 段落p等等,soup 对象本身比较特殊,它的 name 即为 [document]

print(soup.name)
print(soup.title.name)
# [document]
# title

attrs:得到标签属性集合的字典形式,

print(soup.a.attrs)
# {'href': 'https://www.douban.com/accounts/login?source=movie', 'class': ['nav-login'], 'rel': ['nofollow']}

如果我们想要单独获取某个属性,可以这样,例如我们获取a标签的class是什么,两个等价的方法如下:
注意:当属性不存在时,使用 get 返回None,字典形式取值会报错

print(soup.a['href'])
print(soup.a.get('class'))
# https://www.douban.com/accounts/login?source=movie
# https://www.douban.com/accounts/login?source=movie
(2).NavigableString

用 .string获取标签内部的文字
注意:如果该Tag节点仅有单一子节点,将返回最里面的内容,如果有多个子节点,则返回None

print(soup.a.string)
# 登陆
print type(soup.a.string)
# <class 'bs4.element.NavigableString'>

如果遇到多个节点,这个时候需要使用 .strings或者 .stripped_strings(去空白符),进行遍历输出

for s in soup.body.stripped_strings:
    print(s)
(3).BeautifulSoup

BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性:

print type(soup.name)
# <class 'str'>
print soup.name 
# [document]
print soup.attrs 
#{} 空字典
(4).Comment

Comment对象是一个特殊类型的NavigableString对象
标签里的内容是注释,用 .string 来输出它的内容,输出内容将没有注释符号,这可能会给我们带来不必要的麻烦。

if type(soup.a.string)==bs4.element.Comment:
    print soup.a.string

三、遍历文档树

(1)直接子节点(不包含孙节点)

contents: tag的content属性可以将tag的子节点以列表的方式输出

['\n', <script type="text/javascript">var _body_start = new Date();</script>, '\n', <link href="/im....]

children:它返回的不是一个 list,不过我们可以通过遍历获取所有子节点,它是一个 list 生成器对象

for child in soup.body.children:
     print(child)
(2)所有子孙节点

.descendents
以递归形式遍历子孙节点
即先从最外层遍历一遍,之后从其子节点开始遍历,一直到最里层

print(soup.contents)
for i in soup.descendants:
    print(i)
(3)父节点 .parent 所有父节点 .parents 递归形式需要遍历
(4)兄弟节点 .next_sibling, .previous_sibling 加s所有

四、搜索文档树

find_all(name, attrs, recursive, text, limit, **kwargs):
find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。

(1)name参数

1.传递字符串:在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,返回列表。
下面的例子用于查找文档中所有的<a>标签:

print(soup.find_all("a"))

2.传递正则表达式:如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.下面例子中找出所有以b开头的标签,这表示<body><b>标签都应该被找到

import re
for tag in soup.find_all(re.compile("^b")):
    print(tag.name)
# body
# br

3.传递列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回,下面代码找到文档中所有<title>标签和<b>标签

print(soup.find_all(['title','br']))

#<title>
#       豆瓣电影
#</title>
#<br/>

4.传递True: True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点:
5.传方法: 接受一个参数,返回bool值,若为True则表示找到:

def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
(2)attrs参数或者keyword(**kwargs)指定参数
soup.find_all(id="xxx")
soup.find_all(href=re.compile("xxx"))
soup.find_all("a", class_="xxx")
soup.find_all(attrs={"data-foo": "value"})
# 可以同时制定多个属性进行过滤
3)recursive参数
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False。
4)text参数: 通过 text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受字符串 , 正则表达式 , 列表, True。仅返回字符串内容。
soup.find_all(text="豆瓣")
# ['豆瓣', '豆瓣']
5)limit参数
find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果。

猜你喜欢

转载自blog.csdn.net/weixin_42231070/article/details/82225529