二、数据存储

爬虫爬取的数据要经过数据存储步骤存储在磁盘上,对一些数据量较小的项目,数据可以暂时以磁盘文件的形式存储,如果数据量较大,可以选择数据库的方式存储需要的数据。

  1. 以文件方式存储数据
    • 存储为json数据
      使用文件存储数据时,一个不得不说的话题是序列化。在面向对象语言设计中,将一个对象变为一个可以存储、发送的可以恢复出原始对象的字符序列的过程,叫做序列化。将序列化后的字符序列恢复为对象的过程叫做反序列化。经常碰到数据以json对象的方式出现,可以使用python的json模块将对象序列化进文件中保存起来
      #coding:utf-8
      import json
      from bs4 import BeautifulSoup
      import requests
      user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
      headers={'User-Agent':user_agent}
      r = requests.get('http://seputu.com/',headers=headers)
      soup = BeautifulSoup(r.text,'html.parser',from_encoding='utf-8')#html.parser
      content=[]
      for mulu in soup.find_all(class_="mulu"):
          h2 = mulu.find('h2')
          if h2!=None:
              h2_title = h2.string#获取标题
              list=[]
              for a in mulu.find(class_='box').find_all('a'):#获取所有的a标签中url和章节内容
                  href = a.get('href')
                  box_title = a.get('title')
                  list.append({'href':href,'box_title':box_title})
              content.append({'title':h2_title,'content':list})
      with open('test.json','w') as fp:
          json.dump(content,fp=fp,indent=4)
      
    • 存储为csv文件
      csv是一种具有固定格式的表格文件,使用换行符来分隔一行,使用逗号分隔字段,python中使用csv模块操作csv文件。以下程序提取必要信息,存入csv文件中
      import csv
      import re
      from lxml import etree
      import requests
      user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
      headers={'User-Agent':user_agent}
      r = requests.get('http://seputu.com/',headers=headers)
      #使用lxml解析网页
      
      html = etree.HTML(r.text)
      div_mulus = html.xpath('.//*[@class="mulu"]')#先找到所有的div class=mulu标签
      pattern = re.compile(r'\s*\[(.*)\]\s+(.*)')
      rows=[]
      for div_mulu in div_mulus:
          #找到所有的div_h2标签
          div_h2 = div_mulu.xpath('./div[@class="mulu-title"]/center/h2/text()')
          if len(div_h2)> 0:
              h2_title = div_h2[0].encode('utf-8')
              a_s = div_mulu.xpath('./div[@class="box"]/ul/li/a')
              for a in a_s:
                  #找到href属性
                  href=a.xpath('./@href')[0].encode('utf-8')
                  #找到title属性
                  box_title = a.xpath('./@title')[0]
                  pattern = re.compile(r'\s*\[(.*)\]\s+(.*)')
                  match = pattern.search(box_title)
                  if match!=None:
                      date =match.group(1).encode('utf-8')
                      real_title= match.group(2).encode('utf-8')
                      # print real_title
                      content=(h2_title,real_title,href,date)
                      print content
                      rows.append(content)
      headers = ['title','real_title','href','date']
      with open('test.csv','w') as f:
          f_csv = csv.writer(f,)
          f_csv.writerow(headers)
          f_csv.writerows(rows)
      
    • 使用urlretrieve获取多媒体文件
      urllib中的urlretrieve函数可以将多媒体文件下载到本地。以下程序获取天堂图片网的图片,并显示单个图片文件的下载进度
      import urllib
      from lxml import etree
      import requests
      # 下载过程中调用此函数计算进度
      def Schedule(blocknum,blocksize,totalsize):
          '''''
          blocknum:已经下载的数据块
          blocksize:数据块的大小
          totalsize:远程文件的大小
          '''
          per = 100.0 * blocknum * blocksize / totalsize
          if per > 100 :
              per = 100
          print '当前下载进度:%d'%per
      user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
      headers={'User-Agent':user_agent}
      r = requests.get('http://www.ivsky.com/tupian/ziranfengguang/',headers=headers)
      #使用lxml解析网页
      html = etree.HTML(r.text)
      img_urls = html.xpath('.//img/@src')#先找到所有的img
      i=0
      for img_url in img_urls:
          urllib.urlretrieve(img_url,'img'+str(i)+'.jpg',Schedule)
          i+=1
      
  2. 数据库存储
    当项目增大,爬虫数量增多,将数据存储在文件中,不便于维护与数据同步、获取。将数据存储在数据库中,有利于数据存取、备份,提高程序可用性。数据库有关系型和非关系型(Nosql)等类型。关系型数据库的典型代表是mysql,即数据以表的形式被组织起来,字段与字段之间因为处于表中的同一行而可以被互相索引,通过这种个关系将数据组织起来,被称为关系型数据库。随着web数据多样化,简单的关系型数据已经不能满足互联网需求,各种各样的数据包括文本、视频等。非关系型数据库的出现就是为了解决此类问题。非关系型数据库中的文档型和键值型较为常用。记录sqlite、mysql、mongodb数据库的常用操作,方便之后查阅。基本的sql查询语法可以查看菜鸟教程。
    • 使用sqlite
      sqlite是关系型数据库的一种,具有体积小、便携等优点,一个文件即一个数据库,使用十分方便,缺点是并发性不好。
      使用之前使用对应系统的包管理工具安装sqlite数据包即可。使用
      sqlite filename即可创建一个filename命名的数据库
      创建数据库test.db
      sqlite test.db
      创建数据表person,字段有id,name,age
      sqlite> create table person(
      ...> id integer primary key,
      ...> name varchar(20),
      ...> age integer);
      
      向该表中插入数据
      insert into person(name, age) values('xiaozhi', 22);
      .help可以查看sqlite数据库帮助,命令一般以.开头
      可以查看数据表的结构,使用output设置输出,使用dump将数据保存至文件中,设置输出分隔符,保存为csv格式。
      事务是数据库系统的一个重要概念,有时候操作的原子性是很重要的,不能出现前端后台数据不一致的情况,这是不合理的。保证一组操作要么执行完毕,要么不执行,是数据库的事务处理完成的功能。在sqlite中使用start transaction指令开始一个事务,使用commit提交动作,使用roolback回滚操作
      python操作sqlite时,导入标准库sqlite3,基本操作如下
      #coding:utf-8
      import sqlite3
      # 使用connect方法连接/创建数据库,可以创建在内存中
      con = sqlite3.connect('./test.db')#con = sqlite3.connect(':memory:')
      # 使用cursor方法获取操作数据库的游标对象
      cur = con.cursor()
      # 使用cursor对象的execute方法执行sql语句
      cur.execute(' CREATE TABLE person (id integer primary key,name varchar(20),age integer)')
      # 两种传参方式,第二种做了参数化处理,防止sql注入
      data="0,'qiye',20"
      cur.execute(' INSERT INTO person VALUES (%s)'%data)
      
      cur.execute(' INSERT INTO person VALUES (?,?,?)',(0,'qiye',20))
      # 使用executemany执行多条sql语句
      cur.executemany(' INSERT INTO person VALUES (?,?,?)',[(3,'marry',20),(4,'jack',20)])
      
      
      cur.execute('SELECT * FROM person')
      # 使用fetchall获取所有查询结果
      res = cur.fetchall()
      for line in res:
          print line
          cur.execute('SELECT * FROM person')
          res = cur.fetchone()
          print res
      
      cur.execute('UPDATE person SET name=? WHERE id=?',('rose',1))
      cur.execute('DELETE FROM person WHERE id=?',(0,))
      # 使用commit方法提交动作
      con.commit()
      con.close()
      # 《python爬虫开发与项目实战》
      
    • mysql数据库
      mysql数据库安装不再说明,日常使用我们应该知道怎样连接至本地和远程数据库,数据库权限设置,用户账号密码设置,安全设置,数据库备份设置,数据表更改设置,数据增删查改设置,数据库备份设置,详细参见linux运维内容。python操作mysql数据库使用pymysql,python对数据库操做的封装十分简便、统一
      #coding:utf-8
      
      import pymysql
      # 使用connect方法连接mysql主机
      con = pymysql.connect(host='192.168.56.101', user='xiaozhi', passwd='wodemima', db='test', port=3306, charset='utf8')
      # 得到游标对象
      cur = con.cursor()
      # 执行sql指令
      cur.execute(' CREATE TABLE person (id int not null auto_increment primary key,name varchar(20),age int)')
      data="'qiye',20"
      # 两种传参方式
      cur.execute(' INSERT INTO person (name,age) VALUES (%s)'%data)
      
      cur.execute(' INSERT INTO person (name,age) VALUES (%s,%s)',('qiye',20))
      # 执行多条sql语句
      cur.executemany(' INSERT INTO person (name,age) VALUES (%s,%s)',[('marry',20),('jack',20)])
      # 提交操作
      con.commit()
      
      cur.execute('SELECT * FROM person')
      
      cur.execute('SELECT * FROM person')
      # 使用fetchall获取所有查询数据
      res = cur.fetchall()
      for line in res:
          print line
          cur.execute('SELECT * FROM person')
          res = cur.fetchone()
          print res
      # 更新数据表
      cur.execute('UPDATE person SET name=%s WHERE id=%s', ('rose', 1))
      cur.execute('DELETE FROM person WHERE id=%s', (0,))
      con.commit()
      con.close()
      
    • mongodb,mongodb是文档型数据库,和关系型数据库有许多不同。文档型数据库存储的基本单元是文档,多个文档组成集合collection,由集合组成database。
      #coding:utf-8
      import datetime
      import pymongo
      # 连接mongodb服务
      client = pymongo.MongoClient('mongodb://localhost:27017/')
      # 使用属性的方式得到数据库和集合
      db = client.papers
      
      collection = db.books
      
      book = {"author": "Mike",
       "text": "My first book!",
       "tags": ["爬虫", "python", "网络"],
      "date": datetime.datetime.utcnow()
       }
      # 向集合中插入数据
      book_id= collection .insert(book)
      
      books = [{"author": "Mike",
       "text": "My first book!",
       "tags": ["爬虫", "python", "网络"],
      "date": datetime.datetime.utcnow()
       },{"author": "qiye",
       "text": "My sec book!",
       "tags": ["hack", "python", "渗透"],
      "date": datetime.datetime.utcnow()
       }]
      books_id = collection.insert(books)
      
      
      collection.find_one({"author": "qiye"})
      for book in collection.find():
          print book
      for book in collection.find({"author": "qiye"}):
          print book
      
      collection.find({"author": "qiye"}).count()
      
      collection.update({"author": "qiye"},{"$set":{"text":"python book"}})
      
      collection.remove({"author": "qiye"})
      
      mongodb集群是多台mongodb服务器组合成的集群服务,主节点和从节点通过同步数据完成数据备份,当主节点宕机时,从节点可以代替主节点继续工作,提高系统容错性,搭建mongodb集群作为测试,在本机启动三个mongod服务当作三台主机
      mongod --dbpath=./data1 --replSet=replset &
      mongod --dbpath=./data2 --port 27018 --replSet=replset &
      mongod --dbpath=./data3 --port 27019 --replSet replset &
      

      使用mongo连接主节点进行集群设置



      使该设置生效



      插入数据

      在从节点查询



      python访问mongo集群
      from pymongo import MongoClient
      client = MongoClient('mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1,27019', replicaset='replset')
      print client.test.testdb.find_one()
      
    • redis数据库与python
      #coding:utf-8
      import redis
      r = redis.Redis(host='127.0.0.1', port=6379)
      r.set('name', 'qiye')
      print r.get('name')
      
      '''
      pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
      r = redis.Redis(connection_pool=pool)
      r.set('name', 'qiye')
      print r.get('name')
      '''
      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341