SPIDER-DAY02--数据持久化--mysql,csv,mongodb


电影天堂案例

import requests
import re
import time
import random
?
# http://httpbin.org/get
class DyttSpider:
   def __init__(self):
       self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
       self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
?
   def get_html(self, url):
       """请求 解析 数据处理"""
       # content.decode() 手动转码
       # ignore参数: 忽略转码过程中的异常
       html = requests.get(url=url, headers=self.headers).content.decode('gb2312', 'ignore')
       # 直接调用解析函数
       self.parse_html(html)
?
   def parse_html(self, html):
       """正则解析提取数据"""
       regex = '.*?(.*?)'
       r_list = re.findall(regex, html, re.S)
       for r in r_list:
           item = {}
           item['name'] = r[1]
           item['href'] = 'https://www.dytt8.net' + r[0]
           print(item)
?
   def crawl(self):
       """程序入口函数"""
       for page in range(1, 2):
           page_url = self.url.format(page)
           # 请求解析
           self.get_html(url=page_url)
           # 控制频率
           time.sleep(random.randint(1, 3))
?
if __name__ == '__main__':
   spider = DyttSpider()
   spider.crawl()

1. MySQL数据持久化

1.1 pymysql回顾

  • MySQL建库建表

    create database dyttdb charset utf8;
    use dyttdb;
    create table dytt_tab(
    href varchar(500),
    name varchar(100)
    )charset=utf8;
  • pymysql示例

    """
    库: dyttdb
    表: dytt_tab
    在表中任意插入1条表记录
    """
    import pymysql
    ?
    # 1.创建2个对象(连接对象 游标对象)
    db = pymysql.connect('localhost','root','123456', 'dyttdb', charset='utf8')
    cur = db.cursor()
    # 2.执行sql命令,并提交到数据库执行
    cur.execute('insert into dytt_tab values(%s,%s)', ['http://dhxy.html', '足球小将'])
    db.commit()
    ?
    # 3.关闭断开数据库连接
    cur.close()
    db.close()

1.2 电影天堂数据持久化

import requests
import re
import time
import random
import pymysql
?
class DyttSpider:
  def __init__(self):
      self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
      self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
       # 创建数据库连接对象和游标对象
      self.db = pymysql.connect(
           'localhost','root','123456','dyttdb', charset='utf8'
      )
      self.cur = self.db.cursor()
?
  def get_html(self, url):
       """请求 解析 数据处理"""
       # content.decode() 手动转码
       # ignore参数: 忽略转码过程中的异常
      html = requests.get(url=url, headers=self.headers).content.decode('gb2312', 'ignore')
       # 直接调用解析函数
      self.parse_html(html)
?
  def parse_html(self, html):
       """正则解析提取数据"""
      regex = '.*?(.*?)'
      r_list = re.findall(regex, html, re.S)
      ins = 'insert into dytt_tab values(%s,%s)'
       for r in r_list:
           # 数据存入MySQL数据库
          self.cur.execute(ins, r)
          self.db.commit()
           print(r)
?
  def crawl(self):
       """程序入口函数"""
       for page in range(1, 101):
          page_url = self.url.format(page)
           # 请求解析
          self.get_html(url=page_url)
           # 控制频率
           time.sleep(random.randint(1, 3))
       # 断开数据库连接
      self.cur.close()
      self.db.close()
?
if __name__ == '__main__':
  spider = DyttSpider()
  spider.crawl()

2. CSV数据持久化

2.1 CSV持久化概述

【1】作用
  将爬取的数据存放到本地的csv文件中
?
【2】使用流程
   2.1> 打开csv文件
   2.2> 初始化写入对象
   2.3> 写入数据(参数为列表)
 
【3】示例代码
   import csv
   with open('sky.csv','w') as f:
       writer = csv.writer(f)
       writer.writerow([])

2.2 CSV示例代码

import csv
with open('test.csv','w') as f:
writer = csv.writer(f)
writer.writerow(['超哥哥','25'])

2.3 电影天堂CSV持久化

import requests
import re
import time
import random
import csv
?
# http://httpbin.org/get
class DyttSpider:
   def __init__(self):
       self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
       self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
       # 打开文件并初始化写入对象
       self.f = open('dytt.csv', 'w')
       self.writer = csv.writer(self.f)
?
   def get_html(self, url):
       """请求 解析 数据处理"""
       # content.decode() 手动转码
       # ignore参数: 忽略转码过程中的异常
       html = requests.get(url=url, headers=self.headers).content.decode('gb2312', 'ignore')
       # 直接调用解析函数
       self.parse_html(html)
?
   def parse_html(self, html):
       """正则解析提取数据"""
       regex = '.*?(.*?)'
       r_list = re.findall(regex, html, re.S)
       for r in r_list:
           # 数据存入csv文件中
           self.writer.writerow(r)
           print(r)
?
   def crawl(self):
       """程序入口函数"""
       for page in range(1, 2):
           page_url = self.url.format(page)
           # 请求解析
           self.get_html(url=page_url)
           # 控制频率
           time.sleep(random.randint(1, 3))
       # 关闭文件
       self.f.close()
?
if __name__ == '__main__':
   spider = DyttSpider()
   spider.crawl()

3. MongoDB数据持久化

3.1 MongoDB介绍

【1】MongoDB为非关系型数据库,基于key-value方式存储
【2】MongoDB基于磁盘存储,而Redis基于内存
【3】MongoDB数据类型单一,就是JSON文档
MySQL数据类型:数值类型、字符类型、枚举类型、日期时间类型
Redis数据类型:字符串、列表、哈希、集合、有序集合
MongoDB数据类型: JSON文档
# 此生铭记: MongoDB是基于磁盘存储的非关系型数据库,数据类型很单一,值就是JSON文档
【4】和MySQL对比
MySQL:  库 - 表   - 表记录
MongoDB:库 - 集合 - 文档
【5】特性
MongoDB无需提前建库建集合,直接使用即可,会自动创建

3.2 MongoDB常用命令

【1】进入命令行:  mongo
【2】查看所有库: show dbs
【3】切换库:     use 库名
【4】查看库中集合:show collections | show tables
【5】查看集合文档:db.集合名.find().pretty()
【6】统计文档个数:db.集合名.count()
【7】删除集合:   db.集合名.drop()
【8】删除库:     db.dropDatabase()

3.3 与Python交互

  • pymongo模块

    【1】模块名: pymongo
              sudo pip3 install pymongo
    【2】使用流程
    2.1》创建数据库连接对象
    2.2》创建库对象(库可以不存在)
    2.3》创建集合对象(集合可以不存在)
    2.4》在集合中插入文档
  • 示例代码

    """
    库名: dyttdb
    集合名: dytt_set
    插入1条文档: {'name':'活着','star':'牛犇'}
    """
    import pymongo
    ?
    ?
    # 3个对象:连接对象 库对象 集合对象
    conn = pymongo.MongoClient('localhost', 27017)
    db = conn['dyttdb']
    myset = db['dytt_set']
    ?
    # 集合中插入文档
    myset.insert_one({'name':'活着','star':'牛犇'})
    ?
    # 1. show dbs
    # 2. use dyttdb
    # 3. show collections
    # 4. db.集合名.find().pretty()
    # 5. db.集合名.count()
    # 6. db.dropDatabase()
  • 笔趣阁数据持久化

    import requests
    import re
    import time
    import random
    import pymongo
    ?
    class DyttSpider:
       def __init__(self):
           self.url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'
           self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
           # 创建3个对象(连接对象 库对象和集合对象)
           self.conn = pymongo.MongoClient(
               'localhost', 27017
          )
           self.db = self.conn['dyttdb']
           self.myset = self.db['dytt_set']
    ?
       def get_html(self, url):
           """请求 解析 数据处理"""
           # content.decode() 手动转码
           # ignore参数: 忽略转码过程中的异常
           html = requests.get(url=url, headers=self.headers).content.decode('gb2312', 'ignore')
           # 直接调用解析函数
           self.parse_html(html)
    ?
       def parse_html(self, html):
           """正则解析提取数据"""
           regex = '.*?(.*?)'
           r_list = re.findall(regex, html, re.S)
           for r in r_list:
               item = {}
               item['name'] = r[1]
               item['href'] = 'https://www.dytt8.net' + r[0]
               print(item)
               # 把数据存入mongodb数据库
               self.myset.insert_one(item)
    ?
       def crawl(self):
           """程序入口函数"""
           for page in range(1, 101):
               page_url = self.url.format(page)
               # 请求解析
               self.get_html(url=page_url)
               # 控制频率
               time.sleep(random.randint(1, 3))
    ?
    if __name__ == '__main__':
       spider = DyttSpider()
       spider.crawl()

4. 汽车之家多级页面爬虫

4.1 项目需求

【1】爬取地址
https://www.guazi.com/bj/buy/o1/#bread
       
【2】爬取分析
   *********一级页面需抓取***********
       1、汽车详情页链接
       
   *********二级页面需抓取***********
       1、汽车名字、
       2、行驶里程
       3、排量
       4、变速箱
       5、价格

4.2 项目实现流程

【1】确认数据来源 - 响应内容中存在所抓取数据!!!
【2】找URL地址规律
   第1页: https://www.guazi.com/bj/buy/o1/#bread
   第2页: https://www.guazi.com/bj/buy/o2/#bread
   第n页: https://www.guazi.com/bj/buy/on/#bread
【3】 写正则表达式
   3.1》一级页面正则表达式
       '
  •    3.2》二级页面正则表达式
    '

    (.*?)<.*?
  • (.*?).*?(.*?).*?(.*?).*?(.*?)'
    【4】代码实现
  • 4.3 代码实现

    """
    1、一级页面所抓数据
      1.1 每辆汽车(40辆)详情页的链接
    ?
    2、二级页面所抓数据
      2.1 汽车名称
      2.2 行驶里程
      2.3 排量
      2.4 变速箱
      2.5 价格
    """
    import requests
    import re
    import time
    import random
    from fake_useragent import UserAgent
    ?
    class CarSpider:
       def __init__(self):
           """定义常用变量"""
           self.one_url = 'https://www.guazi.com/bj/buy/o{}/#bread'
    ?
       def get_html(self, url):
           """功能函数1: 请求,发请求获取响应内容"""
           headers = {'User-Agent':UserAgent().random}
           html = requests.get(url=url, headers=headers).text
    ?
           return html
    ?
       def refunc(self, regex, html):
           """功能函数2: 正则解析提取数据"""
           r_list = re.findall(regex, html, re.S)
    ?
           return r_list
    ?
       def parse_html(self, url):
           """爬虫逻辑函数由此开始"""
           # 1.获取一级页面响应内容,并提取每辆汽车详情页链接
           # 2.依次拼接每辆详情页地址,发请求提取详情页数据
           # 3.把结果打印输出(放到字典item中)
           one_html = self.get_html(url)
           one_regex = '
  •        href_list = self.refunc(one_regex, one_html)
           for href in href_list:
               # 获取1辆汽车详情页的具体数据
               self.get_car_info(href)
               # 控制频率
               time.sleep(random.uniform(0, 2))
    ?
       def get_car_info(self, href):
           """获取一辆汽车具体数据的函数"""
           two_url = 'https://www.guazi.com' + href
           two_html = self.get_html(two_url)
           two_regex = '

    (.*?)<.*?
  • (.*?).*?(.*?).*?(.*?).*?(.*?)'
           # car_list:[('名字','里程','排量','变速箱','价格')]
           car_list = self.refunc(two_regex, two_html)
           item = {}
           item['car_name'] = car_list[0][0].strip()
           item['car_km'] = car_list[0][1]
           item['car_displace'] = car_list[0][2]
           item['car_type'] = car_list[0][3]
           item['car_price'] = car_list[0][4]
           print(item)
    ?
       def crawl(self):
           """程序入口函数"""
           for page in range(1, 11):
               page_url = self.one_url.format(page)
               self.parse_html(page_url)
    ?
    if __name__ == '__main__':
       spider = CarSpider()
       spider.crawl()
  • 4.4 练习

    【1】将小说信息存入'MongoDB数据库'
    【2】将小说信息存入'novel_info.csv文件'
    【3】将小说信息存入'MySQL数据库'

    5. 增量爬虫

    5.1 增量爬虫概述

    【1】引言
    	当我们在浏览相关网页的时候会发现,某些网站定时会在原有网页数据的基础上更新一批数据,
    	例:1. 某电影网站会实时更新一批最近热门的电影
    	    2. 小说网站会根据作者创作的进度实时更新最新的章节数据等等
    	当我们在爬虫的过程中遇到时,我们是否需要只爬取网站中最近更新的数据,而不每次都做全量爬虫呢?
    
    【2】概念
    	通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据

    5.2 增量爬虫实现

    【1】原理
    	1.1》在发送请求之前判断这个URL是不是之前爬取过
        	适用场景:'不断有新页面出现的网站,比如说小说的新章节,每天的最新新闻等'
    	1.2》在解析内容后判断这部分内容是不是之前爬取过
        	适用场景:'页面内容会更新的网站'
    
    【2】实现
    	2.1》将爬取过程中产生的url进行存储,存储在redis的set中。当下次进行数据爬取时,首先对即将要发起的请求对应的url在存储的url的set中做判断,如果存在则不进行请求,否则才进行请求。
    	2.2》对爬取到的网页内容进行唯一标识的制定,然后将该唯一表示存储至redis的set中。当下次爬取到网页数据的时候,在进行持久化存储之前,首先可以先判断该数据的唯一标识在redis的set中是否存在,在决定是否进行持久化存储

    5.3 瓜子二手车增量爬虫

    """
    1、一级页面所抓数据
       1.1 每辆汽车(40辆)详情页的链接
    
    2、二级页面所抓数据
       2.1 汽车名称
       2.2 行驶里程
       2.3 排量
       2.4 变速箱
       2.5 价格
    """
    import requests
    import re
    import time
    import random
    from fake_useragent import UserAgent
    import redis
    from hashlib import md5
    
    class CarSpider:
        def __init__(self):
            """定义常用变量"""
            self.one_url = 'https://www.guazi.com/bj/buy/o{}/#bread'
            # 连接redis
            self.r = redis.Redis(
                host='localhost', port=6379, db=0
            )
    
        def get_html(self, url):
            """功能函数1: 请求,发请求获取响应内容"""
            headers = {'User-Agent':UserAgent().random}
            html = requests.get(url=url, headers=headers).text
    
            return html
    
        def refunc(self, regex, html):
            """功能函数2: 正则解析提取数据"""
            r_list = re.findall(regex, html, re.S)
    
            return r_list
    
        def md5_href(self, href):
            """功能函数3:md5加密"""
            m = md5()
            m.update(href.encode())
    
            return m.hexdigest()
    
        def parse_html(self, url):
            """爬虫逻辑函数由此开始"""
            # 1.获取一级页面响应内容,并提取每辆汽车详情页链接
            # 2.依次拼接每辆详情页地址,发请求提取详情页数据
            # 3.把结果打印输出(放到字典item中)
            one_html = self.get_html(url)
            one_regex = '
  • 6. 今日作业

    【1】仔细回顾瓜子二手车案例代码
        
    【2】正则抓取豆瓣图书top250书籍信息
    	地址:https://book.douban.com/top250?icn=index-book250-all
        抓取目标:书籍名称、书籍信息、书籍评分、书籍评论人数、书籍描述
        
    【3】电影天堂二级页面数据抓取
    	一级页面:电影详情页链接
        二级页面:电影名称、电影的下载链接
        要求:做成增量爬虫