![Python3网络爬虫宝典](https://wfqqreader-1252317822.image.myqcloud.com/cover/331/33831331/b_33831331.jpg)
1.5 数据存储
顺利地发出网络请求并从响应正文中提取出想要的内容后,便要考虑如何将内容保存起来。数据的存储方式通常由需求方决定,如果需求方没有指定存储方式,则由爬虫工程师自己选择。
文字类数据通常存储在数据库中,例如MySQL数据库、MongoDB数据库或者Redis数据库。文件存储在服务器硬盘中,再将存储路径存储到数据库里。商品类数据或者后续用于分析的数据通常会存储在CSV或者xls文件中。将数据存储在文本文件中的情况比较少,但也不能忽略。
本节我们将学习如何将文字类数据存储到数据库中,如何存储文件类数据,如何将数据存储到xls文件中。
1.5.1 将数据存入MySQL数据库
MySQL是一款免费的关系型数据库,它免费且简单易用的特点使得它深受开发者的喜爱。Python连接或操作MySQL数据库时需要使用专门的连接库,例如PyMySQL。我们可以通过PyMySQL来操作MySQL数据库,例如创建数据库、创建数据表、写入数据、读取数据和删除数据等。
在开始学习之前,请按照MySQL官方文档的指引安装MySQL数据库。接着使用Python的包管理工具安装PyMySQL库,对应的安装命令如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_75.jpg?sign=1739353019-VNrmUCZiYADg8jjbRlDh9VI6htqE1Sou-0-ea2f6a8bd071a63b4b512cee13dce2bd)
假设MySQL中有一个名为books的数据库,数据库里有一张名为ranking的数据表,其内容如表1-3所示。
表1-3 数据表ranking内容示意
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_76.jpg?sign=1739353019-RD2aZFFMQs6Ir4kljvMFRF10t5csWC9y-0-1610a5278e7a9f9a2499adf02b8fe3d0)
接下来我们将围绕这张数据表执行一系列操作,以了解PyMySQL的基本使用方法。首先编写连接数据库的代码:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_77.jpg?sign=1739353019-2WefGz81T1J63cUOUS1j0zgiKaCAcpfp-0-f88f77bdbe50d4eba9f3a44136768eeb)
PyMySQL提供了execute()方法,我们可以将数据库操作语句以字符串的方式传入,包括查询语句、更新语句和删除语句等。查询数据表ranking中所有数据的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_78.jpg?sign=1739353019-pXLk4wfLLjqblC3Iex9ZToV6c73oB7xj-0-d522029acc7cbaaefb57776c0001b217)
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_79.jpg?sign=1739353019-el0qKzM4IJO7zG1lrnRgayobUiRkAQKX-0-a31a5975dfc2576ab2ab9404de6a8c7b)
代码执行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_80.jpg?sign=1739353019-Q1r3WlKfgSh26skv4THXszQt94RN17Sv-0-a0ef40d48e6869f921837ec7254b8e40)
执行fetchall()方法后返回了一个列表对象,列表中以字典形式存储着数据库中的行数据。假设我们需要逐条打印书籍信息,那么我们可以用 for 循环,对应的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_81.jpg?sign=1739353019-9maByanb3H1Sf2KkiKEJ3CLzZVPt0IRl-0-0c979fcf499b91832346b400ef2aaf14)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_82.jpg?sign=1739353019-e1idgpfgwxMhFCy2NpujSmv3PjMUQxhX-0-5198970dd6959289831ca5486c6145c4)
假设我们需要更新《Python3反爬虫原理与绕过实战》的价格,对应语句为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_83.jpg?sign=1739353019-uNsytHiWJrjqxyuLRHLk4ONIIJqCEjPO-0-49643c7d536b8d46f5c8b2c3c219df01)
这段代码执行后并不会输出或打印结果,要想查看结果我们可以再次执行上一次的查询代码和循环代码,代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_84.jpg?sign=1739353019-1lBA3jzR56hB7kF4IX9hx6V18P4IY4Cb-0-552504f91a064c980112cdc0fdad2e03)
图书《Python3反爬虫原理与绕过实战》的价格由89.0变成了66.7,说明更新语句执行成功。假设我们从网页提取的数据存放在对象data中,那么将data逐一添加到数据库的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_85.jpg?sign=1739353019-UJg046rxiHZWPDfeemItbDeGuGLwLZMV-0-ccc463aa041a4e5e6554db9e1faa1dfa)
代码运行后,数据库中的数据如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_86.jpg?sign=1739353019-ewRQdicu7olL4HVsGxt7D7xxXBWB60Aq-0-5fc1e6d2253998e4c11f870dc171e1c4)
这说明数据已经存入了数据库中。以上就是使用PyMySQL操作MySQL数据库的基本方法,更多知识请翻阅PyMySQL官方文档。
1.5.2 将数据存入MongoDB数据库
MongoDB是一款基于分布式文件存储的非关系型数据库。MongoDB数据库不需要提前设置字段名称和对应的类型,使用时直接写入即可。同一个集合可以存储不同结构的文档,就算缺少字段也不会影响数据的写入。这两个特点正是它成为最受爬虫工程师欢迎的数据库的原因。
Python连接或操作MongoDB数据库时需要使用专门的连接库,例如PyMongo。我们可以通过PyMongo来操作MongoDB数据库,例如创建数据库、创建集合、写入文档、读取文档和删除文档等。
在开始学习之前,请按照MongoDB官方文档的指引安装MongoDB数据库。接着使用Python的包管理工具安装PyMongo库,对应的安装命令如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_87.jpg?sign=1739353019-IXSXkHzgssi3Q4nNwF0Md3V0JOzbJvtu-0-38172124e4ae9aac514e65dbe5287b93)
由于MongoDB不需要提前建立数据库和集合,所以我们可以在代码中指定任意名称的数据库和集合。首先编写连接数据库的代码,并指定数据库名为books,指定集合名称为ranking:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_88.jpg?sign=1739353019-WiBNzf7Wg9LtCJgtBBfywW9nMCWsfd50-0-799e276cffcf365a60bb069f8604e393)
假设我们从网页提取的数据存放在对象data中,那么将data添加到数据库的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_89.jpg?sign=1739353019-DSN2ipTHgutrgMpdhm5UUrIiuAZi2sA6-0-e40547547f4b7cc0c1c1253c5a7725a5)
从MongoDB中查询数据也很简单,代码如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_90.jpg?sign=1739353019-uRtfBbiyMzOC2r1VukfbUzw0Z0SWaljz-0-70b0d2a7110865a4861ad76461ecbb08)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_91.jpg?sign=1739353019-yKArZzrkBbnKIzukdiSN8sAVQLAjafov-0-aff3d00b395fdc64bb7208303c6368fb)
这里的_id是MongoDB自动为文档生成的唯一ID。当我们想要从数据库中查询指定的数据时,可以指定_id或者指定查询条件,例如查询价格大于50.0的书籍信息:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_92.jpg?sign=1739353019-gzWPL2yfdTkpmBaaH79K078NutVXGwmF-0-ee4fd93a76e18f0bbf8801053fb5a1e2)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_93.jpg?sign=1739353019-4BbIJ6CGMiKG5T45kJWdH0DqzRVGWl7y-0-38c7b23a887e25a0ebc0e5606f4af1b7)
假设我们需要将图书《Go语言核心编程》的状态改为ON,则对应的代码如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_94.jpg?sign=1739353019-lLL9JKqZfFQtaXjICgBcazR8F4jx4MFA-0-a9f2cb1d164786ddb77f4481a6934858)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_95.jpg?sign=1739353019-Fp38hO9jTL9iq3IhG7kVdvEnz6scw0Sa-0-7340bbe718cb12aa7fe5df75d825d8a0)
运行结果说明我们已经成功地修改了图书《Go语言核心编程》的状态。熟悉MongoDB的读者会发现,PyMongo的语法与MongoDB原生语法十分接近,包括条件筛选、联合查询和删除操作。这样的设计减少了使用者的学习成本,这也是PyMongo库深受爬虫工程师欢迎的原因之一。
以上就是PyMongo操作MongoDB数据库的基本方法,更多知识请翻阅PyMongo官方文档。
1.5.3 将数据存入Redis数据库
Redis是目前流行的且性能极高的Key-Value数据库,爬虫工程师在设计分布式爬虫架构时通常会将Redis考虑到其中。与MySQL和MongoDB数据库相同的是,Python连接或操作Redis数据库时也需要使用专门的连接库,例如redis库。我们可以通过redis库来操作Redis数据库,例如创建集合、写入数据、读取数据和删除数据等。
在开始学习之前,请按照Redis官方文档的指引安装Redis数据库。接着使用Python的包管理工具安装redis库,对应的安装命令如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_96.jpg?sign=1739353019-9ItLk1vVzN0gsNhsvSrquRoNOnEUTJ0A-0-f457f7ffdda2283aafbc36a99cd31479)
首先编写连接数据库的代码:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_97.jpg?sign=1739353019-WHrnhpHalyBGKd9sGpy3GhGq8JpnTBG4-0-eb101a0519759ab0a62ae6ee8712e988)
假设我们需要在Redis数据库中新建一个名为ranking的集合,并将爬虫爬取到的书籍信息写入到ranking中,对应的代码如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_98.jpg?sign=1739353019-ujmhC1coxfvXvZPlrGSRyHrhrr5n59vp-0-6b3d912b80a001cc7478d5d3ab258a25)
查询Redis数据库中ranking集合数据的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_99.jpg?sign=1739353019-55yiqEPWlznJ9z6lnBbyyd64vesEUY5M-0-66a576f9c2ff0480eb2088207ab8083f)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_100.jpg?sign=1739353019-ujjzz34GCJZyW061ldcZLAqfovUKLY6R-0-80e7239749f01416117f075c217548af)
假设我们需要查询集合中存储了多少条数据,可以用SCARD命令,对应的代码如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_101.jpg?sign=1739353019-LAlpqZZfoCJZpURCVQLix7kqUE9tnuJQ-0-6fdef54647c3fc2030af2824692254b3)
输出结果为3。
在实际的爬虫程序编写过程中,我们很有可能遇到这样的一种需求:数据条数满100条时存储1次,以达到降低数据库I/O消耗的目的。这种需求我们可以借助redis库提供的pipeline()方法实现,对应的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_102.jpg?sign=1739353019-xjwLGcGXpfDX0kj0l0ZMdmj1lTaC6YMG-0-8ab40b0e2cf63c615a28b28c18eeabe6)
待写入数据总数为1008条,每100条写入1次。考虑到剩下的8不满足100条的条件,遂在for循环外再调用一次execute()方法。代码运行后,Redis数据库中ranking集合的数据条数如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_103.jpg?sign=1739353019-iznSwTY55WduF7UNpH1ZOgWiOpTPrVfG-0-4df7147d9b7966f4a7bc0e886289b7fd)
之前有3条数据,加上这次写入的1008条,共1011条,说明数据已经成功写入Redis数据库中。
跟PyMongo语法和MongoDB语法的关系一样,redis库的语法与Redis数据库原生语法也十分接近,只要了解Redis数据库的语法,一定能够快速掌握redis库的基本用法。
以上就是使用redis库操作Redis数据库的基本方法,更多知识请翻阅redis库的官方文档。
1.5.4 Excel文件的读写
Python对文件的读写有着原生的支持,我们只需要调用内置的open()函数或者使用上下文管理器with open()的方式创建一个文件并将内容写入即可。我们可以将str格式的文字写入到文本文件中,也可以将图片的bytes数据以wb模式写入到文件中,并用.png或.jpg等作为文件后缀。图片爬取和存储的代码片段如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_104.jpg?sign=1739353019-YbNstUBQBKexNzEDCKdVS9wR0PRXOsrq-0-e18be1e2b88246759c3ff22d37caf65d)
代码逻辑很简单,导入Requests库后调用get()方法向电子工业出版社官网LOGO图片的网址发出请求,然后提取bytes格式的响应信息,接着创建一个名为logo、后缀为.jpg的文件,并将bytes格式的响应信息写入文件。代码运行后,logo.jpg文件就会生成,图片如图1-32所示。
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_105.jpg?sign=1739353019-0DUjjtt4h0rsOwOGSQg8iZnvucB9k7Ts-0-03233bfb9d7b4d116241c3b3032bb747)
图1-32 logo.jpg
如果想要将数据按照一定格式存入Excel文档对应的xls文件中,可就没那么简单了。Python官方并不支持特定的文件格式,我们需要借助其他开发者编写的库向Excel文档写入数据或者从Excel文档中读取数据。Python开发者用得最多的Excel库分别是xlwt和xlrd,其中xlwt用于向Excel文档写入数据,xlrd用于从Excel文档读取数据。我们可以使用Python的包管理工具安装这两个库,对应的安装命令如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_106.jpg?sign=1739353019-8g8px7Hd8f6lCQhUGMrdHkhpBB7n5GZh-0-29ef21a0931c7f167d91dabd8c674dd3)
根据xlwt库的文档示例,我们可以很快地写出创建Excel文档、向文档指定的行和指定的列写入数据的代码。例如,创建一个名为abs.xls的文件,并在第1个Sheet的第1行第1列写入“你好”,对应的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_107.jpg?sign=1739353019-61gfiXmrQzbihvNjRkdrTKp8iaeZWPhF-0-cc8f47814b5bce605f7bf8513047d82e)
代码运行后,我们就会在目录中找到程序创建的abs.xls文件,打开后可以看到我们成功地将“你好”写入到指定的位置。接下来我们将在这个基础上增加一些难度,例如将一个列表中的数据存入Excel文档:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_108.jpg?sign=1739353019-Yyslv2krXYsUMsXkqQUiJMAxCnFkMViR-0-46b6ed6a315c7489df7bfbd498cf9f26)
这里用了for循环将列表中的数据一条一条地写入Excel文档的指定位置。代码运行后我们将在名为simple的Excel文件中看到如表1-4所示的信息。
表1-4 Excel文件内容
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_109.jpg?sign=1739353019-YsM7OdGqAG8X4gpmcRlrLloT8oz09NWs-0-4d9bab850c99e81305c187eb73a5ffa3)
在第三方库的帮助下,Excel 文档的写入工作变得很轻松,相信读取工作也一样轻松。假设我们需要从simple.xls文件中读取刚才写入的数据,对应的代码为:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_110.jpg?sign=1739353019-6wzcJqrO4lN9y3igzLXZh7ZnhgTtOjyj-0-11d7b6d1336c38d8fcc0d1474f0c99a2)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_111.jpg?sign=1739353019-Ue8SQtqKOTy0hkz703tNpQI3KUHDxP3K-0-1e98490843e8c545950561bf4c3fd126)
虽然成功地输出了Excel文件中的信息,但是似乎没有结构和顺序,我们试试看能不能将它们恢复成原来的结构。首先我们需要准备一个名为info的空列表,用于存放所有数据,然后再准备一个空的字典用于存放每一行不同列的数据,接着通过for循环行和for循环列将单元格中的数据取出来,并按照循环时的顺序将数据添加到字典中。我们只需要改动for循环部分的代码即可,对应改动如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_112.jpg?sign=1739353019-qANkQZB6pHC5a7YzIHS9lwTrhNxRw0wH-0-94188f5faa42b26159c34243a8bc6ae3)
代码运行结果如下:
![img](https://epubservercos.yuewen.com/141F12/18096061008240606/epubprivate/OEBPS/Images/txt001_113.jpg?sign=1739353019-HjoyQjBpqegaKn06PpSMiA5j0kn09Gk1-0-5994d2b5ff81d39ff492e7e7eaea038f)
运行结果说明我们成功地将Excel文档中的数据还原为存储前的格式。
以上就是使用xlwt和xlrd库读写Excel文档的基本方法,更多知识请翻阅对应的文档。