IT Xiao Ang Zai 2019年3月27号
版本:python3.7
编程软件:Pycharm,Sublime Text 3
前面我们已经能够用requests库把网页的源代码爬取下来,而且还用了selenium模拟浏览器爬取了里面的信息,其实就是解析网页。但selenium的速度比较慢,而且每次都需要打开网页,因此,实际上不用该方法解析网页。这里我们先介绍三中常用的解析网页的方法,之后再展示其他更高级的操作。
一:正则表达式
有关正则表达式的东西之前就已经介绍过了,说白了就是用一个字符串匹配模式规则在源代码中匹配我们需要的字符串。这里就不详讲了。
二:BeautifulSoup模块
(1)介绍:BeautifulSoup可以从HTML或XML文件中提取数据,是一个很方便的第三方库。
(2)支持的解析器:BeautifulSoup支持Python标准库的HTML解析器,还支持一些第三方的解析器。常用的如下:
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | Beautiful(text,"html.parser") | Python的内置标准库,容错强,速度适中 | 老版本容错能力差 |
lxml HTML解析器 | BeautifulSoup(text,"lxml") | 速度快,容错强 | 需要安装c语言库 |
lxml XML解析器 | BeautifulSoup(text,["lxml","xml"]) BeautifulSoup(text,"xml") |
速度快,唯一支持XML的解析器 | 需要安装c语言库 |
html5lib | BeautifulSoup(text,"html5lib") | 容错最好 | 速度慢 |
注:通常用lxml解析器更好一些。
(3)BeautifulSoup获取网页的内容的过程:
其实,BeautifulSoup对象是一个复杂的树形结构,每一个节点都是一个Python对象,获取内容就是从该树形结构中遍历,然后获取我们需要的内容。而提取对象的方法可以有三种。
第一种:遍历文档树
该方法就像是爬树一样,一步一步爬取数据在soup对象后用点操作符(.)就可以得到。下面还有一些常用的方法:
contents | 把标签的子节点以列表方式输出 |
children | 获取所有的子标签 |
descendants | 获取所有子孙结点 |
parent | 获取父节点 |
第二种:搜索文档树
该方法用得多,最常用的是find()和find_all(),它还可以配合正则表达式使用。
第三种:CSS选择器
可以在遍历文档树和搜索文档树时使用CSS选择器。
语法为:soup.select("CSS选择器")
三:使用lxml解析网页
1.除了前面的两种方法,还有其他的用来解析网页的库,用的是Xpath语法(如lxml),用C语言编写,解析速度要更快一点。
2.安装lxml
直接用语句:
pip install lxml
注:在Pycharm中需要用设置安装。
3.Xpath选择器
lxml用来提取网页数据的常用方法就是用Xpath选择器,用路径表达式选取结点。用法如下:
表达式 | 描述 |
---|---|
nodename | 选取该节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
其实lxml语法也是很难进行判断的,但我们可以在网页检查元素中找到xpath,因此就把困难的问题变简单了。
四:三种解析方法的比较
如果面对的是很复杂的网页源码,则正则表达式的书写会很费时间。由于BeautifulSoup中也有lxml解析器,因此它的速度和lxml差不多,对于熟悉XPath的人来说,可以选择lxml。不过如果把握不好正则表达式,以及对Xpath语法不熟悉,则使用BeautifulSoup的find和find_all的方法会比较方便。
前面讲到解析网页的方法,我们可以选择其中一种方法获得数据,但数据获得后需要先存储下来,方便应用程序或者其他地方调用,下面就介绍两种常用的存储数据的方法。
五:数据存储到文件中
1.存储到txt或excel文件中
这种方法是最常见的,这里就不叙述了,大家可以看我之前的文章进行复习:
https://blog.csdn.net/ITxiaoangzai/article/details/81336090
2.存储到csv文件中
(1)csv文件(逗号分隔值文件格式)介绍:逗号分隔值(Comma-Separated Values,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。
规则如下:
<1> 开头是不留空,以行为单位。
<2> 可含或不含列名,含列名则居文件第一行。
<3> 一行数据不跨行,无空行。
<4> 以半角逗号(即,)作分隔符,列为空也要表达其存在。
<5>列内容如存在半角引号(即"),替换成半角双引号("")转义,即用半角引号(即"")将该字段值包含起来。
<6>文件读写时引号,逗号操作规则互逆。
<7>内码格式不限,可为 ASCII、Unicode 或者其他。
(2)打开方式:记事本或Excel。
(3)python读写csv文件
方法:python读取csv文件,用的是csv模块。
代码步骤:
a:读入csv文件
import csv
with open("文件","r") as f:
csv_reader = csv.reader(f)
for i in csv_reader:
print(i)
注:i为列表,相当于把对象csv_reader按每一行数据转化为列表中输出,输出的都是字符串。
b:写入csv文件
可以把变量写入列表中,然后用writerow()方法把一个列表直接写入一列中。
代码步骤如下:
import csv
output = ['1','2','3','4']
with open("文件","a+") as k:
w = csv.writer(k)
w.writerow(output)
注:要先把变量转化为字符串才能够写入。
六:存储到数据库中
上面介绍了把数据存储到文件中去,但有时候数据较多,且要对数据进行大量的增,删,查,改等操作,就需要用到数据库了。下面就介绍吧数据存储到MySQL数据库和MongoDB数据库中的方法。
1.存储至MySQL数据库
(1)简介:它是一种关系型数据库,使用的是SQL语言。关系型数据库建立在关系模型基础上,它将数据保存在不同的表中,这样就使得数据更方便写入和读取,数据的存储也可以灵活掌握。
(2)优点:体积小,速度快而且免费。关于MySQL的语法这里就不介绍了。
下面介绍三种python操作mysql数据库的方法,在连接时,一定要指定是哪个数据库,否则会报错。
(3)mysql-connector驱动器连接使用MySQL
该驱动器是官方提供的驱动器,用来连接使用MySQL:
先安装如下:
下面是一些基本方法:
mydb = mysql.connector.connect) | 创建数据库连接(可指定用户名(user),密码(passwd),主机(host)和数据库名称(db)等信息) |
mycursor = conn.cursor() | 创建游标 |
mycursor.execute() | 通过游标操作execute()方法可以写入纯SQL语句 |
mycursor.close() | 关闭游标 |
mydb.commit() | 连接创建的数据库 |
mydb.close() | 断开数据库连接 |
关于MySQL的基本语句这里就不说明了,下面介绍一些python操作mysql的方法:
executemany()方法:可以批量插入多条数据。
mycursor.lastrowid()方法:获取该纪录的ID。
mycursor.fetchall()方法:获取所有记录。
mycousor.fetchone()方法:只读取一条数据。
mycusor.rowcount()方法:这是一个只读属性,并返回执行execute()方法后影响的行数
(3)python2旧版本操作MySQL数据库
首先先安装mysqlclient库,连接python和MySQL:
下面是一些方法:
conn = MySQLdb.connect() | 创建数据库连接(可指定用户名(user),密码(passwd),主机(host)和数据库名称(db)等信息) |
cur = conn.cursor() | 创建游标 |
cur.execute() | 通过游标操作execute()方法可以写入纯SQL语句 |
cur.close() | 关闭游标 |
conn.commit() | 连接创建的数据库连接 |
conn.close() | 断开数据库连接 |
如果输入的是中文数据的话,需要在连接数据库时将编码指定为UTF-8,用charset="utf-8"语句。
在python3中也可以使用MySQLdb库。
(4)python3中新版本操作数据库
在python3中,用PyMySQL库连接和操作数据库。
先安装该库:
语句和上面的类似。
(5)实例创建数据库对象
接下来用第一种数据库引擎创建mysql数据库对象,这里用Navicat for MySQL图形化数据库管理工具进行可视化,其他的数据库类似。
先创建一个数据库:
然后输入下面代码:
#coding = UTF-8
import mysql.connector
mydb = mysql.connector.connect( #创建数据库连接
host = "localhost",
user = "root",
password = "abc3158276",
database = "我的第一个数据库",
charset = "utf8", #如果数据库中有中文,需要指定数据库
)
# 插入单行数据
mycursor = mydb.cursor() #创建游标
mycursor.execute("CREATE TABLE 食物( id INT NOT NULL,foodname VARCHAR(1000) NOT NULL,foodprice INT NOT NULL,PRIMARY KEY(id))")
sql = "INSERT INTO 食物 (id,foodname,foodprice) VALUES (%s,%s,%s)"
id = "1"
foodname = "香蕉"
foodprice = "54"
values = (id,foodname,foodprice)
mycursor.execute(sql,values)
#插入多行数据
sql2 = "INSERT INTO 食物 (id,foodname,foodprice) VALUE (%s,%s,%s)"
things = [
("2",'西瓜',"46"),
("3",'苹果',"25"),
("4",'菠萝',"17"),
("5",'西红柿',"75"),
("6",'猕猴桃',"46"),
("7",'其他',"00"),
]
mycursor.executemany(sql2,things)
#查询所有数据
mycursor.execute("SELECT * FROM 食物")
all_database = mycursor.fetchall()
for i in all_database:
print(i)
print("\n")
#查询各自的属性
mycursor.execute("SELECT id FROM 食物")
id_all = mycursor.fetchall()
for j in id_all:
print(j)
print("\n")
mycursor.execute("SELECT foodname,foodprice FROM 食物")
foodthing_one = mycursor.fetchone()
print(foodthing_one)
mycursor.close()
mydb.commit()
结果如下:
其他的操作这里就不一一说明了,不过这三种的写法类似,在实际应用中可以选择一种写法。
(6)MongoDB数据库
在网络爬虫中,有很多时候爬取的都是json格式的字符串,这时候用关系型数据库,就会是的表读写困难,结构更改困难。而使用非关系型数据库,就会容易扩展,数据之间无关系,具有很高的读写性能。
而NoSQL数据库中的MongoDB数据库,是一个基于分布式文件的数据库,有很高的可扩展性,因此使用很方便。
关于MongoDB数据库的安装与基础知识这里就不详讲了,之后有用到的地方再详讲,有需要的同学可以自学。
注:还有一些其他的数据库,比如SQLLite,这里就不详细说明了。在后面的实例中,如果有用到数据库时,配合爬虫一般就是用MySQL数据库和MongoDB数据库。