数据存储
一、文件存储
为什么需要文件存储?
爬虫在抓取数据后,需要对抓取到的这些数据进行分析,分析完之后需要将有用的数据进行保存。保存数据有很多种方式,其中最简单的就是将数据保存在二进制文件或文本文件中。这些文件主要包括XML文件、CSV文件、JSON文件。
在对文件进行操作时,涉及到打开文件,读取文件内容,向文件写入内容,关闭文件。方法分别是(open,read,write,close)。
下面我主要讲解JSON格式字符串,因为JSON格式的数据现在被广泛用于各种应用中
首先讲一下JSON格式与字典的区别:字典的值可以是任意类型,但是JSON格式的数据的键都要用双引号括起来,且不能使用单引号。JSON格式的数据可以保存数组和对象,JSON数组用一对中括号将数据括起来,JSON对象用一对大括号括起来。
1、JSON字符串与字典互相转换
在这里,大家需要认真看,因为很容易搞混淆(一下是我对这些函数方法的看法,如果有错误,还请大家指出)
①:将字典转换为JSON字符串需要使用json模块的dumps函数
②:将字典写入json文件需要使用json模块的dump函数
③:将json字符串转换为字典需要使用json模块的loads函数
④:将json字符串写入普通文件中需要使用load函数,在普通文件中,会以字典的形式出现
⑤:使用eval函数将json格式的字符串当作普通的python代码执行,eval函数会直接返回与json格式字符串对应的字典
import json
data = {
'name':'Bill',
'company':'microsoft',
'age':34
}
#将字典转换为json格式
jsonStr = json.dumps(data)
#输出变量类型
print(type(jsonStr))
print(jsonStr)
#将json转换为字典
dictStr = json.loads(jsonStr)
#输出变量类型
print(type(dictStr))
print(dictStr)
#定义一个json字符串
s = '''
{
'name':'bill',
'company':'Microsoft',
'age':38
}
'''
#使用eval函数将json字符串转换为字典
data = eval(s)
print(type(data))
print(data)
print(data['company'])
<class 'str'>
{"name": "Bill", "company": "microsoft", "age": 34}
<class 'dict'>
{'name': 'Bill', 'company': 'microsoft', 'age': 34}
<class 'dict'>
{'name': 'bill', 'company': 'Microsoft', 'age': 38}
Microsoft
2、JSON字符串与类实例互相转换
使用loads函数和dumps函数可以实现。看下面的示例:
import json
class Product:
#d参数是要传入的字典
def __init__(self,d):
self.__dict__ = d
#r表示只读
f = open("product.json",'r')
jsonStr = f.read()
my1 = json.loads(jsonStr,object_hook=Product)
print(my1.name)
print(my1.price)
print(my1.color)
#记住需要关闭文件,否则可能出现一些问题
f.close()
#运行结果
HuaWei
9999
red
注意:其实在这里还涉及一些数据库的存储操作,比较复杂,如果有感兴趣的,可以和我私底下交流,虽然我也不是很了解,但是期待和大家一起学习。
看了几个我写的爬虫代码,大家可以发现,其实大部分的代码都是重复的,学习反爬手段后,我们可能就需要进行一些其他操作,大家放心,后面我还会对反爬进行学习,现在我们爬取的基本上都是一些反爬能力较低的网站,接下来我就爬取两个网站来练习练习,如果有对爬虫方面的知识感兴趣的同学,一定要多尝试爬取数据,这样对自己知识的掌握更好
实战案例:豆瓣音乐排行榜(https://music.douban.com)
"""
首先对网页进行分析
第一步:获得每个音乐的链接,然后进入URL
第二步:分析网页代码,使用自己习惯的方式获取信息
第三步:需要抓取的数据:图片链接,歌曲名,表演者
第四步:保存数据
"""
import requests
from lxml import etree
from bs4 import BeautifulSoup
import os
import random
import time
from UA_info import ua_list
class DouMusicSpider(object):
os_path = os.getcwd()+'/豆瓣音乐/'
if not os.path.exists(os_path):
os.mkdir(os_path)
def __init__(self):
self.headers = {
'User-Agent':random.choice(ua_list)
}
#本次采用了两次解析URL网页,第一次获得音乐相关的链接,然后在对该链接进行解析
def get_first_html(self):
for i in range(0,251,25):
url = f'https://music.douban.com/top250?start={i}'
response = requests.get(url,headers=self.headers)
if response.status_code == 200:
html = response.text
soup = BeautifulSoup(html,'lxml')
href_lists = soup.select('a.nbg')
for href_list in href_lists:
href = href_list['href']
self.get_second_html(href)
def get_second_html(self,href):
response = requests.get(url=href,headers=self.headers)
html = response.text
self.parse_html(html)
#本人更喜欢使用xpath解析语法
def parse_html(self,html):
xml = etree.HTML(html)
#获取图片链接
img_src_list = xml.xpath('//a[@class="nbg"]/img/@src')
#获取表演者
acter_list = xml.xpath('//div[@id="info"]//span/a/text()')
#获取歌曲名
title_list = xml.xpath('//div[@id="wrapper"]/h1/span/text()')
for img_src,acter,title in zip(img_src_list,acter_list,title_list):
data = {
'acter':acter,
'title':title,
'img_src':img_src
}
img = requests.get(img_src).content
self.save_data(title,acter,img)
time.sleep(1)
print(f"{acter}的歌曲《{title}》图片正在下载中!!!")
time.sleep(0.5)
print(data)
def save_data(self,title,acter,img):
with open(self.os_path+f'{acter}--{title}'+'.jpg','wb') as f:
f.write(img)
if __name__ == '__main__':
douban = DouMusicSpider()
douban.get_first_html()
{'acter': '陈绮贞', 'title': '华丽的冒险', 'img_src': 'https://img9.doubanio.com/view/subject/m/public/s1441645.jpg'}
周杰伦的歌曲《范特西》图片正在下载中!!!
{'acter': '周杰伦', 'title': '范特西', 'img_src': 'https://img3.doubanio.com/view/subject/m/public/s3750422.jpg'}
五月天的歌曲《後。青春期的詩》图片正在下载中!!!
{'acter': '五月天', 'title': '後。青春期的詩', 'img_src': 'https://img3.doubanio.com/view/subject/m/public/s3316597.jpg'}
孙燕姿的歌曲《是时候》图片正在下载中!!!
{'acter': '孙燕姿', 'title': '是时候', 'img_src': 'https://img3.doubanio.com/view/subject/m/public/s4653287.jpg'}
Lenka的歌曲《Lenka》图片正在下载中!!!
{'acter': 'Lenka', 'title': 'Lenka', 'img_src': 'https://img9.doubanio.com/view/subject/m/public/s3259484.jpg'}
实战案例:爬取豆瓣电影TOP250(https://movie.douban.com)
"""
第一步:获得电影的链接
第二步:获取想要的内容,电影名,导演,图片,简介
第三步:将获取的图片和简介进行保存
"""
import requests
from lxml import etree
import time
import re
import os
from bs4 import BeautifulSoup
import random
from UA_info import ua_list
class MovieSpider:
os_path = os.getcwd()+'/豆瓣电影TOP250/'
if not os.path.exists(os_path):
os.mkdir(os_path)
def __init__(self):
self.headers = {
'User-Agent':random.choice(ua_list)
}
def get_first_html(self):
for i in range(0,101,25):
url = f'https://movie.douban.com/top250?start={i}&filter='
response = requests.get(url,headers=self.headers)
if response.status_code == 200:
lxml = etree.HTML(response.text)
href_list = lxml.xpath('//div[@class="hd"]/a/@href')
for href in href_list:
self.get_second_href(href)
def get_second_href(self,href):
response = requests.get(url=href,headers=self.headers)
html = response.text
self.parse_html(html)
def parse_html(self,html):
lxml = etree.HTML(html)
#获取图片链接
img_src = lxml.xpath('//div[@id="mainpic"]//img/@src')
img_src = img_src[0]
#获取电影名
title = lxml.xpath('//div[@id="content"]//h1/span/text()')
title = title[0].split(' ')[0]
#获取导演
soup = BeautifulSoup(html,'lxml')
director = soup.select('#info > span:nth-child(1) > span.attrs > a')
director = director[0].get_text()
#获取简介,有时候不一定xpath语法就非常好,本来一开始爬取这个我使用xpath,发现很难,后来用了正则
#所以大家尽量多学习一些解析语法,对自己有很大的帮助
content = re.findall('<span\sproperty="v:summary".*?>\n(.*?)\n.*?<br.*?>',html,re.S)
contents = content[0].split('\u3000\u3000')[1]
data = {
'title':title,
'director':director
}
img = requests.get(img_src).content
self.save_data(title,img,contents)
print(f'{title}正在下载中!!!!!!!!!!!!!')
time.sleep(2)
print(data)
def save_data(self,title,img,content):
file = self.os_path+f'/{title}/'
if not os.path.exists(file):
os.mkdir(file)
with open(file+title+'.jpg','wb') as f:
f.write(img)
with open(file+title+'.txt','w',encoding='utf-8') as f:
f.write(content)
if __name__ == '__main__':
douban = MovieSpider()
douban.get_first_html()
肖申克的救赎正在下载中!!!!!!!!!!!!!
{'title': '肖申克的救赎', 'director': '弗兰克·德拉邦特'}
霸王别姬正在下载中!!!!!!!!!!!!!
{'title': '霸王别姬', 'director': '陈凯歌'}
阿甘正传正在下载中!!!!!!!!!!!!!
{'title': '阿甘正传', 'director': '罗伯特·泽米吉斯'}
泰坦尼克号正在下载中!!!!!!!!!!!!!
{'title': '泰坦尼克号', 'director': '詹姆斯·卡梅隆'}
这个杀手不太冷正在下载中!!!!!!!!!!!!!
{'title': '这个杀手不太冷', 'director': '吕克·贝松'}
千与千寻正在下载中!!!!!!!!!!!!!
{'title': '千与千寻', 'director': '宫崎骏'}