wjx-2005-07-01  

数据存储

一、文件存储

为什么需要文件存储?

爬虫在抓取数据后,需要对抓取到的这些数据进行分析,分析完之后需要将有用的数据进行保存。保存数据有很多种方式,其中最简单的就是将数据保存在二进制文件或文本文件中。这些文件主要包括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': '宫崎骏'}
posted on 2024-01-18 19:51  星辰与Python  阅读(28)  评论(0编辑  收藏  举报