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 = '<td height="26">.*?<a href="(.*?)" class="ulink">(.*?)</a>'
       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 = '<td height="26">.*?<a href="(.*?)" class="ulink">(.*?)</a>'
      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 = '<td height="26">.*?<a href="(.*?)" class="ulink">(.*?)</a>'
       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 = '<td height="26">.*?<a href="(.*?)" class="ulink">(.*?)</a>'
           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》一级页面正则表达式
       '<li data-scroll-track=.*?href="(.*?)"'
   3.2》二级页面正则表达式
'<h1 class="titlebox">(.*?)<.*?<li class="two"><span>(.*?)</span>.*?<span>(.*?)</span>.*?<span>(.*?)</span>.*?<span class="price-num">(.*?)</span>'
【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 = '<li data-scroll-track=.*?href="(.*?)"'
       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 = '<h1 class="titlebox">(.*?)<.*?<li class="two"><span>(.*?)</span>.*?<span>(.*?)</span>.*?<span>(.*?)</span>.*?<span class="price-num">(.*?)</span>'
       # 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 = '<li data-scroll-track=.*?href="(.*?)"'
        href_list = self.refunc(one_regex, one_html)
        for href in href_list:
            # 生成指纹
            finger = self.md5_href(href)
            # 返回值1: 没抓过
            if self.r.sadd('car:spiders', finger) == 1:
                self.get_car_info(href)
                # 控制频率
                time.sleep(random.uniform(0, 2))
            else:
                print(finger,'之前已抓取')

    def get_car_info(self, href):
        """获取一辆汽车具体数据的函数"""
        two_url = 'https://www.guazi.com' + href
        two_html = self.get_html(two_url)
        two_regex = '<h1 class="titlebox">(.*?)<.*?<li class="two"><span>(.*?)</span>.*?<span>(.*?)</span>.*?<span>(.*?)</span>.*?<span class="price-num">(.*?)</span>'
        # 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, 2):
            page_url = self.one_url.format(page)
            self.parse_html(page_url)

if __name__ == '__main__':
    spider = CarSpider()
    spider.crawl()




"""
create database cardb charset utf8;
use cardb;
create table car_tab(
car_name varchar(300),
car_km varchar(200),
car_displace varchar(200),
car_type varchar(200),
car_price varchar(200)
)charset=utf8;
"""

6. 今日作业

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

 

 

 

 

 

posted @   我不知道取什么名字好  阅读(223)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示