c爬虫抓取网页数据(Python的内置标准库、执行速度适中、文档容错能力强 )
优采云 发布时间: 2021-10-17 06:18c爬虫抓取网页数据(Python的内置标准库、执行速度适中、文档容错能力强
)
1、基本情况
对于静态网页,您只需要应用两个库,requests 库和 BeautifulSoup4 库。
1.1简介
Beautiful Soup 是一个python库,主要功能是抓取网页数据。
BeautifulSoup4 是爬虫必备的技能。 BeautifulSoup 的主要功能是从网页中抓取数据。
Beautiful Soup 自动将输入文档转换为 Unicode 编码,输出文档为 utf-8 编码。
BeautifulSoup 支持 Python 标准库中的 HTML 解析器,以及一些第三方解析器。如果我们不安装它,Python 将使用 Python 默认解析器。 lxml 解析器功能更强大,速度更快。推荐使用lxml解析器。
Beautiful Soup 提供了一些简单的 Python 风格的函数来处理导航、搜索、修改分析树等功能。
1.2安装
安装:pip install beautifulsoup4
导入:导入bs4(注意不能导入beautifulsoup)
1.3 种主要解析器的比较
使用解析器的优缺点
Python 标准库
BeautifulSoup(markup, “html.parser”)
Python内置标准库,执行速度适中,文档容错能力强
Python 2.7.3 or 3.2.2)之前的版本中文容错能力差
lxml HTML 解析器
BeautifulSoup(markup, “lxml”)
速度快,文档容错能力强
需要安装C语言库
lxml XML 解析器
BeautifulSoup(markup, “xml”)
速度快,唯一支持XML的解析器
需要安装C语言库
html5lib
BeautifulSoup(markup, “html5lib”)
最佳容错性,浏览器解析文档,生成HTML5格式文档
速度慢,不依赖外部扩展
2、基本使用方法
基本用法如下:
代码示例:
import requests
from bs4 import BeautifulSoup
url = "http://jinyongxiaoshuo.com/xueshanfeihu/489.html"
#要爬取的网页,这里我找了个金庸小说的网页
res = requests.get('https://cuiqingcai.com/authors/%E5%B4%94%E5%BA%86%E6%89%8D/page/2/')
#向网页发送请求
res.encoding='utf-8'
#编码为utf-8模式
soup=BeautifulSoup(res.text,'html.parser')
#用Python自带的解析器‘html.parser’解析
print(soup)
#打印出整个HTML文档
3、BeautifulSoup4 四种对象
BeautifulSoup4 将复杂的 HTML 文档转换成复杂的树结构,每个节点都是一个 Python 对象,所有对象可以归纳为 4 种类型:
3.1.标签
我们可以通过使用soup 和标签名称轻松获取这些标签的内容。这些对象的类型是 bs4.element.Tag。但请注意,它会查找所有内容中满足要求的第一个标签。
print(type(bs.a))
对于 Tag,它有两个重要的属性,name 和 attrs:
3.2.NavigableString
既然我们已经拿到了标签的内容,那么问题来了,如果我们想要拿到标签里面的文字,我们应该怎么做呢?很简单,直接用.string
print(type(bs.title.string))
3.3.美汤
BeautifulSoup 对象表示文档的内容。大多数时候,它可以看作是一个 Tag 对象,是一个特殊的 Tag。我们可以分别获取它的类型、名称和属性
3.4.评论
注释对象是一种特殊类型的 NavigableString 对象,其输出不收录注释符号。
4、遍历文档树
4.1、.contents:获取Tag的所有子节点并返回一个列表
# tag的.content 属性可以将tag的子节点以列表的方式输出
print(bs.head.contents)
# 用列表索引来获取它的某一个元素
print(bs.head.contents[1])
4.2、.children:获取Tag的所有子节点并返回一个*敏*感*词*
for child in bs.body.children:
print(child)
4.3、.descendants:获取Tag的所有后代
4.4、.strings:如果Tag收录多个字符串,也就是后代节点有内容,可以用这个获取,然后遍历
4.5、.stripped_strings:与字符串的用法一致,只是可以去掉多余的空白内容
4.6、.parent:获取Tag的父节点
4.7、.parents:递归获取父元素的所有节点并返回一个*敏*感*词*
4.8、.previous_sibling:获取当前Tag的上一个节点。该属性通常是字符串或空白。真正的结果是当前标签和前一个标签之间的逗号和换行符。
4.9、.next_sibling:获取当前Tag的下一个节点。该属性通常是字符串或空白。结果是当前标签和下一个标签之间的逗号和换行符。
4.10、.previous_siblings:获取当前Tag之上的所有兄弟节点,并返回一个*敏*感*词*
4.11、.next_siblings:获取当前Tag下的所有兄弟节点,并返回一个*敏*感*词*
4.12、.previous_element:获取解析过程中最后解析的对象(字符串或标签),可能与previous_sibling相同,但通常不同
4.13、.next_element:获取解析过程中下一个要解析的对象(字符串或标签),可能与next_sibling相同,但通常不同
4.14、.previous_elements:返回一个*敏*感*词*向前访问文档的解析内容
4.15、.next_elements:返回一个*敏*感*词*,允许您向后访问文档的解析内容
4.16、.has_attr:判断标签是否收录属性
5、搜索文档树
5.1find_all( name, attrs, recursive, text, **kwargs )
find_all()方法查找当前标签的所有标签子节点,判断是否满足过滤条件
5.1.1name 参数
name参数可以找到所有名为name的标签,string对象会被自动忽略。
5.1.1.传输字符串
最简单的过滤器是一个字符串。在搜索方法中传入一个字符串参数,Beautiful Soup 会找到与字符串完全匹配的内容。以下示例用于查找文档中的所有标签
soup.find_all('b')
# [The Dormouse's story]
print soup.find_all('a')
5.1.1.B 传正则表达式
如果传入一个正则表达式作为参数,Beautiful Soup会通过正则表达式的match()来匹配内容。在下面的例子中,所有以 b 开头的标签都被找到了,这意味着应该找到 and 标签。
import re
for tag in soup.find_all(re.compile("^b")): print(tag.name)
# body
# b
5.1.1.C.传输列表
如果传入 list 参数,Beautiful Soup 将返回匹配列表中任何元素的内容。以下代码查找文档中的所有标签和标签
soup.find_all(["a", "b"])
# [<b>The Dormouse's story,
# Elsie,
# Lacie,
# Tillie]
5.1.1.D.通过真
True 可以匹配任何值,以下代码查找所有标签,但不会返回字符串节点
for tag in soup.find_all(True):
print(tag.name)
# html
# head
# title
# body
# p
# b
# p
# a
# a
5.1.1.E.传输方式
如果没有合适的过滤器,那么也可以定义一个方法,该方法只接受一个元素参数[4],如果这个方法返回True,则表示匹配并找到当前元素,如果没有,则返回错误
以下方法验证当前元素。如果它收录 class 属性但不收录 id 属性,它将返回 True:
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
#将这个方法作为参数传入 find_all() 方法,将得到所有<p>标签:
soup.find_all(has_class_but_no_id)
# [<p class="title">The Dormouse's story,
#
Once upon a time there were...,
#
...]</p>
5.1.2、关键字参数
注意:如果指定名称的参数不是搜索内置参数名称,则搜索时将作为指定名称标签的属性进行搜索。如果收录一个名为 id 的参数,Beautiful Soup 会搜索每个标签的“Id”属性
soup.find_all(id='link2')
# [Lacie]
如果传入href参数,Beautiful Soup会搜索每个标签的“href”属性
soup.find_all(href=re.compile("elsie"))
# [Elsie]
使用指定名称的多个参数同时过滤标签的多个属性
soup.find_all(href=re.compile("elsie"), id='link1')
# [three]
这里想按class过滤,class是python的关键词,怎么办?加一个下划线
soup.find_all("a", class_="sister")
# [Elsie,
# Lacie,
# Tillie]
有些标签属性不能用于搜索,比如HTML5中的data-*属性
soup.find_all("a", class_="sister")
# [Elsie,
# Lacie,
# Tillie]
但是可以通过find_all()方法的attrs参数定义一个字典参数来搜索收录特殊属性的标签
data_soup.find_all(attrs={"data-foo": "value"})
# [foo!]
5.1.3、文本参数
文档中的字符串内容可以通过text参数进行搜索。与name参数的可选值一样,text参数接受字符串、正则表达式、列表和True
soup.find_all(text="Elsie")
# [u'Elsie']
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(text=re.compile("Dormouse"))
#[u"The Dormouse's story", u"The Dormouse's story"]
5.1.4、限制参数
find_all() 方法返回所有搜索结构。如果文档树很大,搜索会很慢。如果我们不需要所有的结果,我们可以使用 limit 参数来限制返回结果的数量。作用类似于SQL中的limit关键字,当搜索结果数达到limit限制时,停止搜索返回结果。
文档树中有3个标签符合搜索条件,但由于我们限制了返回次数,只返回了2个结果
soup.find_all("a", limit=2)
# [Elsie,
# Lacie]
5.1.5、递归参数
当调用标签的 find_all() 方法时,Beautiful Soup 将检索当前标签的所有后代。如果只想搜索标签的直接子节点,可以使用参数 recursive=False 。
一个简单的文档:
复制代码代码如下:
The Dormouse's story
是否使用递归参数搜索结果:
soup.html.find_all("title")
# [The Dormouse's story]
soup.html.find_all("title", recursive=False)
# []
5.2、find( name, attrs, recursive, text, **kwargs )
它和find_all()方法唯一的区别是find_all()方法的返回结果是一个收录一个元素的值列表,而find()方法直接返回结果
5.3、find_parents(), find_parent()
find_all() 和 find() 只搜索当前节点的所有子节点、孙节点等。 find_parents() 和 find_parent() 用于搜索当前节点的父节点。查找方法与普通标签相同。搜索文档 搜索文档收录内容
5.4、find_next_siblings() find_next_sibling()
这两个方法使用.next_siblings属性来迭代所有后面解析的兄弟标签节点。一个标签节点
5.5、find_previous_siblings() find_previous_sibling()
这两个方法使用 .previous_siblings 属性来迭代当前标签之前解析的兄弟标签节点。 find_previous_siblings() 方法返回之前所有满足条件的兄弟节点, find_previous_sibling() 方法返回第一个满足条件的兄弟节点。兄弟节点
5.6、find_all_next() find_next()
这两个方法使用 .next_elements 属性来迭代当前标签之后的标签和字符串。 find_all_next() 方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点
5.7、find_all_previous() 和 find_previous()
这两个方法使用 .previous_elements 属性来迭代当前节点前面的标签和字符串。 find_all_previous() 方法返回所有符合条件的节点, find_previous() 方法返回第一个符合条件的节点
<p>注意:上述5.2--5.7方法参数用法与find_all()完全相同,原理也类似,这里不再赘述。