前言
python实现网络爬虫非常简单,只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点,方便以后复习。
申明
本系列所涉及的代码仅用于个人研究与讨论,并不会对网站产生不好影响。
目录结构
bs4是BeautifulSoup4的简称,它是一个可以从HTML中提取数据的Python第三方库,也是我们将要讲解的第二个解析库,除此之外,还有常用的pyquery(主要通过css语法来获取,我们不讲解,因为需要学习过前端的css)、re(正则表达式库,基础库,但是用于爬虫里比较麻烦,因此也不讲解)。
其安装非常简单:
pip install Beautifulsoup4
对于bs4这个库来说,我们主要使用的是BeautifulSoup对象,使用方法如下:
# 导包
from bs4 import BeautifulSoup
# 创建对象
soup = BeautifulSoup()
print(type(soup))
# 结果为:
#
而BeautifulSoup在解析网页的时候依赖于其他的解析器,如我们之前讲解过的lxml等等。下面给出常见的四种解析器:Python标准库、lxml解析器、xml解析器、html5lib解析器。上面四种解析器各有优点也有缺点,其中最常用的就是lxml,因为其解析速度和容错性都比较好。
下面给出四种解析器的优缺点:
解析器 | 优点 | 缺点 |
---|---|---|
Python标准库 | python内置标准库,执行速度适中,文档容错强 | python2.x与python3.2.2之前的版本容错能力差 |
lxml | 速度快、容错能力强 | 需要安装C语言库 |
xml | 速度快,唯一支持XML文档的解析器 | 需要安装C语言库 |
html5lib | 最好的容错性 | 速度慢 |
什么是容错性?
这里解释一下,什么是容错性。我们有时候传给BeautifulSoup的网页源代码并不完整,或者说格式不标准,其中常见的如:table标签的写法,table标签现在一般都采取的简写的方式,而不是标准的写法。这时,不同的解析器就有不同的容错性,或者说对于修正性。
下面给出bs4的一个小小例子,让大家有一个印象:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 提取出 所有类名
tag_list = soup.find_all('a')
for tag in tag_list:
print(tag.text)
结果为:
4K风景
4K美女
4K游戏
4K动漫
4K影视
4K明星
4K汽车
4K动物
4K人物
4K美食
4K宗教
4K背景
跟lxml一样,第一个步骤仍然是初始化,这个步骤是固定的,就不多说了,代码如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# text为html源码,字符串格式
第一个选择元素的方法,如下示例;
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 方法一
result = soup.div
print(type(result))
print('-'*50)
print(result)
结果如下:
<class 'bs4.element.Tag'>
--------------------------------------------------
<div class="classify clearfix">
<a href="/4kfengjing/" title="4K风景图片">4K风景a>
<a href="/4kmeinv/" title="4K美女图片">4K美女a>
<a href="/4kyouxi/" title="4K游戏图片">4K游戏a>
<a class="curr" href="/4kdongman/" title="4K动漫图片">4K动漫a>
<a href="/4kyingshi/" title="4K影视图片">4K影视a>
<a href="/4kmingxing/" title="4K明星图片">4K明星a>
<a href="/4kqiche/" title="4K汽车图片">4K汽车a>
<a href="/4kdongwu/" title="4K动物图片">4K动物a>
<a href="/4krenwu/" title="4K人物图片">4K人物a>
<a href="/4kmeishi/" title="4K美食图片">4K美食a>
<a href="/4kzongjiao/" title="4K宗教图片">4K宗教a>
<a href="/4kbeijing/" title="4K背景图片">4K背景a>
div>
可见,这种方法的语法形式为: xxx.Tag_name。这种选择还支持嵌套选择,如下:
# 为了大家方便,省略了相同的代码,下面只给出需要修改的代码
# 修改之前:result = soup.div
# 修改之后:
result = soup.div.a
结果为::
--------------------------------------------------
4K风景
可见,当有多个符合条件的标签时,选择第一个符合的标签。
缺点:选择性很低,无法增加附加条件进行更深层次的筛选。
小小的总结一下:
1. xxx.Tag_name
2. 当有多个符合条件的标签时,选择第一个符合的标签。
主要依靠一些属性来获取,如:contents、children、descendants等等。下面一一讲解其作用:
子节点
属性: contents、children
作用: 获取目标的直接子节点
注意:contents返回的是列表,而children返回的是生成器。
比如:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 方法二
print(type(soup.div.contents))
for child in soup.div.contents:
print(child)
结果为:
<class 'list'>
<a href="/4kfengjing/" title="4K风景图片">4K风景a>
<a href="/4kmeinv/" title="4K美女图片">4K美女a>
<a href="/4kyouxi/" title="4K游戏图片">4K游戏a>
<a class="curr" href="/4kdongman/" title="4K动漫图片">4K动漫a>
<a href="/4kyingshi/" title="4K影视图片">4K影视a>
<a href="/4kmingxing/" title="4K明星图片">4K明星a>
<a href="/4kqiche/" title="4K汽车图片">4K汽车a>
<a href="/4kdongwu/" title="4K动物图片">4K动物a>
<a href="/4krenwu/" title="4K人物图片">4K人物a>
<a href="/4kmeishi/" title="4K美食图片">4K美食a>
<a href="/4kzongjiao/" title="4K宗教图片">4K宗教a>
<a href="/4kbeijing/" title="4K背景图片">4K背景a>
子孙节点:
属性: descendants
作用: 获取目标的所有子孙元素
返回值: 生成器
比如:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 方法二
print(type(soup.ul.descendants))
for child in soup.ul.descendants:
print(child)
结果:
<class 'generator'>
# 显示其中一个结果
# 从下面可以看出,一一获取里面所有的值
<li>
<a href="/tupian/26783.html" target="_blank">
<img alt="动漫女孩 黑发 露肩 4k壁纸3840x2160" src="/uploads/allimg/210122/210154-16113205145cce.jpg"/>
<b>动漫女孩 黑发 露肩 4k壁</b>
</a>
</li>
<a href="/tupian/26783.html" target="_blank">
<img alt="动漫女孩 黑发 露肩 4k壁纸3840x2160" src="/uploads/allimg/210122/210154-16113205145cce.jpg"/>
<b>动漫女孩 黑发 露肩 4k壁</b>
</a>
<img alt="动漫女孩 黑发 露肩 4k壁纸3840x2160" src="/uploads/allimg/210122/210154-16113205145cce.jpg"/>
<b>动漫女孩 黑发 露肩 4k壁</b>
动漫女孩 黑发 露肩 4k壁
父节点:
属性: parent
作用: 获取目标节点的父节点
祖先节点:
属性: parents
作用: 获取目标节点的所有祖先节点
返回值: 生成器
兄弟节点:
属性1 : next_sibling
作用: 获取下一个兄弟节点
属性2 : previous_sibling
作用: 获取上一个兄弟节点
属性3: next_siblings
作用: 获取下面的所有兄弟节点
属性4: previous_siblings
作用: 获取之前的所有兄弟节点
find_all()方法:
作用: 查询出所有符合条件的元素
常用参数: name、attrs、text
参数讲解:
示例一:name 和 attrs 的配合使用
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 筛选出白菜
result_list = soup.find_all('a',attrs={'class':'white'})
print(type(result_list))
print('-'*50)
for result in result_list:
print(result)
结果:
<class 'bs4.element.ResultSet'>
--------------------------------------------------
<a class="white" href="/tupian/26783.html" target="_blank">白菜a>
<a class="white" href="/tupian/26783.html" target="_blank">白菜a>
<a class="white" href="/tupian/26783.html" target="_blank">白菜a>
<a class="white" href="/tupian/26783.html" target="_blank">白菜a>
示例二: text的使用
import re
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 筛选出白菜
result_list = soup.find_all(text=re.compile(r'白菜'))
for result in result_list:
print(result)
结果为:
白菜,你好,我是黑菜
白菜,你好,你好
我是一个小白菜
大白菜
find()方法:
作用: 返回第一个匹配成功的元素
find_parents()和find_parent():
find_parents():返回所有的祖先节点
find_parent():返回直接父节点
find_next_siblings()和find_next_sibling():
find_next_siblings(): 返回后面所有的兄弟节点
find_next_sibling(): 返回下一个兄弟节点
find_previous_siblings()和find_previous_sibling():
find_previous_siblings(): 返回之前的所有的兄弟节点
find_previous_sibling(): 返回上一个兄弟节点
如果你学过css,那么你也可以采取css来写,不过我建议你选择pyquery模块来写css,因为pyquery专门使用css来解析网页。
写法:
xxx.select('css代码 ')
作用:
返回所有符合css条件的元素
示例:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 筛选出白菜
result_list = soup.select('.white')
for result in result_list:
print(result)
结果如下:
<a class="white" href="/tupian/26783.html" target="_blank">白菜,你好,我是黑菜a>
<a class="white" href="/tupian/26783.html" target="_blank">白菜,你好,你好a>
<a class="white" href="/tupian/26783.html" target="_blank">我是一个小白菜a>
<a class="white" href="/tupian/26783.html" target="_blank">大白菜a>
元素筛选成功后,我们需要获取元素的一定信息,如:文本信息、属性信息等等。
获取文本信息:
xxx.string:
用来获取目标路径下第一个非标签字符串,得到的是个字符串
xxx.stings:
用来获取目标路径下所有的子孙非标签字符串,返回的是个生成器
xxx.stripped_strings:
用来获取目标路径下所有的子孙非标签字符串,会自动去掉空白字符串,返回的是一个生成器
xxx.get_text():
用来获取目标路径下的子孙字符串,返回的是字符串(包含HTML的格式内容)
示例:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 筛选出白菜
tag = soup.find('li')
print(tag.string)
print(list(tag.strings))
print(list(tag.stripped_strings))
print(tag.get_text())
结果如下:
None
['\n', '你好', '\n', '白菜,你好,我是黑菜', '\n', '白菜,你好,你好', '\n', '我是一个小白菜', '\n', '大白菜', '\n', '黑彩', '\n']
['你好', '白菜,你好,我是黑菜', '白菜,你好,你好', '我是一个小白菜', '大白菜', '黑彩']
你好
白菜,你好,我是黑菜
白菜,你好,你好
我是一个小白菜
大白菜
黑彩
获取属性信息:
xxx.attrs['属性名字']
xxx['属性名字']
示例:
from bs4 import BeautifulSoup
text = '''
'''
soup = BeautifulSoup(text,'lxml') # 需要安装lxml库哦
# 筛选出白菜
tag_list = soup.find_all('a')
tag_attr_list_one = [tag.attrs['class'] for tag in tag_list]
tag_attr_list_two = [tag['class'] for tag in tag_list]
print(tag_attr_list_one)
print('-'*50)
print(tag_attr_list_two)
结果:
[['hello'], ['white'], ['white'], ['white'], ['white'], ['black']]
--------------------------------------------------
[['hello'], ['white'], ['white'], ['white'], ['white'], ['black']]
本篇讲解了第二个解析库bs4,当然其实大家不需要了解那么多的解析库,会一两个即可,因此本系列也只讲解lxml、bs4这两个用到最多的解析库,其他的比如pyquery、re都可以自己去学习。
下一篇会将之前的小说实战重新采用bs4来解析。