Python项目----基于Scrapy爬虫框架的豆瓣电影数据采集

项目介绍

项目简介

  • 项目名称:《基于Scrapy爬虫框架的豆瓣电影数据采集》
  • 项目领域:大数据采集

项目开发环境

  • 编程语言:Python 3.6.5
  • 开发IDE:PyCharm
  • 使用技术:Scrapy框架
  • 数据库:MySQL
  • 数据库IDE:SQLYOG

项目需求分析

  • 爬虫主程序数据采集模块
  • 多元数据持久化模块
  • 二进制数据采集模块
  • 深度自动采集模块
  • 日志系统模块

Scrapy框架

Scrapy框架基础知识

Scrapy框架概念
Scrapy是一个为了爬取网站数据提取结构性数据而编写的应用框架。
Scrapy框架功能
爬虫程序基于Scrapy框架创建,借助于Scrapy的item以及pipeline功能实现数据抽取,并将爬取的数据存储到item中。最后通过pipeline对数据进一步处理(存储、打印)。
在这里插入图片描述
在这里插入图片描述

Scrapy框架安装

安装第三方爬虫离线包
在DOS环境下安装第三方爬虫离线包:

E:\>pip install Twisted-18.4.0-cp36-cp36m-win_amd64.whl
Processing e:\twisted-18.4.0-cp36-cp36m-win_amd64.whl

安装Scrapy爬虫框架

E:\>pip install -U scrapy
Collecting scrapy

查看框架版本号

E:\>pip install scrapy==
Collecting scrapy==

用固定版本号安装

E:\>pip install scrapy==1.5.0
Collecting scrapy==1.5.0

Scrapy框架使用

  1. 创建一个Scrapy项目
    scrapy startproject 项目名
scrapy startproject doubanmov;
  1. 生成一个爬虫
    scrapy genspider 脚本程序名称 域名
scrapy genspider movie "douban.com”
  1. 提取数据
    完善spider,使用xpath等方法
  2. 保存数据
    pipeline管道中保存数据

项目功能实现

爬虫主程序数据采集模块

数据信息采集

  1. 定义item字段数据(items.py),
  2. 使用XPATH定位并解析网页源代码,并获取所需要的“电影排名”和“电影名称”数据文本(movie.py)。
  3. 将采集数据已生成器方式返回至item。
import scrapy

class DoubanmovItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    #排名
    rank = scrapy.Field()
    #电影名称
    title = scrapy.Field()
    #电影图片
    pic = scrapy.Field()
import scrapy
import re
import math
from doubanmov.items import DoubanmovItem
from doubanmov.logmessage import clogger

class MovieSpider(scrapy.Spider):
    name = 'movie'
    allowed_domains = ['douban.com']
    #爬取首地址
    start_urls = ['https://movie.douban.com/top250']
    def __init__(self):
        self.log = clogger.demo()
    def parse(self, response):
        #定位采集数据的标签
        items_mov = response.xpath('//div[@class="item"]')
        #遍历结果
        for items in items_mov:
            #创建采集对象
            mov = DoubanmovItem()
            #排名#XPATH解析并赋值
            mov['rank'] = items.xpath('div[@class="pic"]/em/text()').extract()
            # 名字解析并赋值
            mov['title'] = items.xpath('div[@class="info"]/div[@class="hd"]/a/span[@class="title"][1]/text()').extract()
            mov['pic'] =items.xpath('div[@class="pic"]/a/img/@src').extract()
            #生成生成器输出
            yield mov

实现403反爬虫

  1. 禁用框架自带的浏览器标识(settings.py)
  2. 重新设置浏览器标识(rotate_useragent.py)
  3. 使用IP代理器
# 导入random模块
import random
# 导入useragent用户代理模块中的UserAgentMiddleware类
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware

# RotateUserAgentMiddleware类,继承 UserAgentMiddleware 父类
# 作用:创建动态代理列表,随机选取列表中的用户代理头部信息,伪装请求。
#       绑定爬虫程序的每一次请求,一并发送到访问网址。

# 发爬虫技术:由于很多网站设置反爬虫技术,禁止爬虫程序直接访问网页,
#             因此需要创建动态代理,将爬虫程序模拟伪装成浏览器进行网页访问。
class RotateUserAgentMiddleware(UserAgentMiddleware):
    def __init__(self, user_agent=''):
        self.user_agent = user_agent

    def process_request(self, request, spider):
        #这句话用于随机轮换user-agent
        ua = random.choice(self.user_agent_list)
        if ua:
            # 输出自动轮换的user-agent
            print(ua)
            request.headers.setdefault('User-Agent', ua)

    # the default user_agent_list composes chrome,I E,firefox,Mozilla,opera,netscape
    # for more user agent strings,you can find it in http://www.useragentstring.com/pages/useragentstring.php
    # 编写头部请求代理列表
    user_agent_list = [\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"\
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",\
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",\
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",\
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",\
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",\
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
       ]
DOWNLOADER_MIDDLEWARES = {
    'doubanmov.middlewares.DoubanmovDownloaderMiddleware': 543,
    #  禁用框架自带的浏览器标识
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
    # 设置浏览器标识
    'doubanmov.rotate_useragent.RotateUserAgentMiddleware': 400,
}

控制台输出采集结果

  1. 通过Scrapy框架的pipeline管道将需要的数据通过控制台显示。
  2. 开放管道输出
ITEM_PIPELINES = {
   'doubanmov.pipelines.DoubanmovPipeline': 300,
   'doubanmov.pipelinesjson.DoubanmovPipeline': 301,
   'doubanmov.pipelinesexc.DoubanmovPipeline': 302,
   'doubanmov.pipelinesSQL.DoubanmovPipeline': 303,
   'doubanmov.pipelinespic.DoubanmovPipeline': 304,
   'doubanmov.pipelinescsv.DoubanmovPipeline': 305,
   'doubanmov.pipelinesjson1.DoubanmovPipeline': 301,
}
from doubanmov.logmessage import clogger
class DoubanmovPipeline(object):
    def __init__(self):
        self.log1 = clogger.demo()
    def process_item(self, item, spider):
        #管道输出
        try:
            print('电影排名:{0}'.format(item['rank'][0]))
            print('电影名字:<<{0}>>'.format(item['title'][0]))
            self.log1.logginfo('输出了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.log1.loggerror('输出<<{0}>>电影失败'.format(item['title'][0]))
            pass
        return item

多元数据持久化模块

json文件存储

  • 方法一:
  1. 将item数据存储为列表包字典的模式
  2. 通过json.jump()将列表写入json文件
import json
from doubanmov.logmessage import clogger
# list1 = []
class DoubanmovPipeline(object):
    def __init__(self):
        self.list1 = []
        self.log = clogger.demo()
        
    def process_item(self, item, spider):
        try:
            #将item数据存储至字典中
            dict1={'排名':item['rank'][0],'名字':item['title'][0]}
            # 将字典数据追加至列表中中
            self.list1.append(dict1)
            # json文件存储
            with open('data/jsondate.json',mode='w',encoding='utf-8') as file:
                json.dump(self.list1,file,ensure_ascii=False)
            #日志存储
            self.log.logginfo('向"data/jsondate.json"中存储了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.log.loggerror('向"data/jsondate.json"中存储<<{0}>>电影失败'.format(item['title'][0]))
        return item
  • 方法二:
  1. 将爬取的数据存储为字典类型
  2. 将字典数据序列化并增加换行功能
import json
from doubanmov.logmessage import clogger
class DoubanmovPipeline(object):
    def process_item(self, item, spider):
        #获取爬取的数据存成字典模式
        dict1 = {'排名': item['rank'][0], '名字': item['title'][0]}
        #将列表序列化并增加换行
        filejson = json.dumps(dict1, ensure_ascii=False) + '\n'
        #用文本方式存储json数据
        with open('data/jsondate.json', mode='a', encoding='utf-8') as file:
            file.write(filejson)
        return item
  • 方法三:
    利用Scrapy命令存储json文件
#设置存储编码
FEED_EXPORT_ENCODING='UTF-8'
scrapy crawl movie -o myjson.json -t json

csv文件存储

  • 方法一:
  1. 将爬取的数据存储为字典类型
  2. 将字典数据追加至列表
  3. 将列表按表头和内容存储数据
import csv
from doubanmov.logmessage import clogger
class DoubanmovPipeline(object):
    def __init__(self):
        self.list1 = []
        self.log = clogger.demo()

    def process_item(self, item, spider):
        try:
            #爬取数据存储为字典类型
            dict1={'排名':item['rank'][0],'名字':item['title'][0]}
            #将字典数据追加为列表
            self.list1.append(dict1)
            with open('data/movie.csv',mode='w',encoding='utf-8',newline='') as file:
                #csv文件写入
                write = csv.DictWriter(file,self.list1[0])
                # csv文件头写入
                write.writeheader()
                # csv文件内容写入
                write.writerows(self.list1)
            self.log.logginfo('向"data/movie.csv"中存储了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.log.loggerror('向"data/movie.csv"中存储<<{0}>>电影失败'.format(item['title'][0]))
        return item
  • 方法二:
    利用Scrapy命令存储csv文件
#设置存储编码
FEED_EXPORT_ENCODING='UTF-8'
scrapy crawl movie -o mycsv.csv -t csv

Excel文件存储

  1. 创建Excel文件
  2. 获取爬取数据头文件
  3. 将数据存储为列表包列表的模式
  4. 按行和列存储数据至Excel文件
import xlwt
list1=[]
from doubanmov.logmessage import clogger
class DoubanmovPipeline(object):
    def __init__(self):
        # Excel文件创建工作薄
        self.workbook = xlwt.Workbook()
        #获取单页对象
        self.sheet = self.workbook.add_sheet('sheet1')
        #添加数据---文件头写
        self.header = ['电影排名', '电影名字']
        for i in range(len(self.header)):
            self.sheet.write(0, i, self.header[i])
        self.log = clogger.demo()
    def process_item(self, item, spider):
        #添加数据---文件内容获取
        firlist=[item['rank'][0],item['title'][0]]
        list1.append(firlist)
        return item

    def close_spider(self, spider):
        try:
            #按行遍历
            for i in range(1,len(list1)+1):
                #按列遍历
                for j in range(len(self.header)):
                    # 添加数据---文件内容按行列存储
                    self.sheet.write(i,j,list1[i-1][j])
                self.log.logginfo('向"data/movie.xls"中存储了<<{0}>>电影'.format(list1[i - 1][0]))
        except:
            self.log.loggerror('向"data/movie.xls"中存储<<{0}>>电影失败'.format(list1[i - 1][0]))
        #保存Excel文件
        self.workbook.save('data/movie.xls')

Excel文件存储

  1. 连接数据库(主机地址,端口,用户名,密码,数据库名)
  2. 获取数据库对象
  3. 执行SQL语句(增删改查)
  4. 提交事务
import pymysql
from doubanmov.logmessage import clogger
list1=[]
class DoubanmovPipeline(object):
    def __init__(self):
        # 连接数据库
        self.con = pymysql.connect(host='localhost', port=3306, user='root', passwd='root', db='db_movie', )
        # 获取游标对象
        self.cur = self.con.cursor()
        self.log = clogger.demo()
    def process_item(self, item, spider):
        #执行SQL语句
        try:
            self.cur.execute('insert into movie values(%d,"%s")' %(int(item["rank"][0]),item["title"][0]))
            #提交事务
            self.con.commit()
            self.log.logginfo('向数据库中存储了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.con.rollback()
            self.log.loggerror('向数据库中存储<<{0}>>电影失败'.format(item['title'][0]))
        return item
    def close_spider(self,spider):
        self.cur.close()
        self.con.close()

xml文件存储

利用Scrapy命令存储xml文件

#设置存储编码
FEED_EXPORT_ENCODING='UTF-8'
scrapy crawl movie -o myxml.xml -t xml

二进制数据采集模块

  1. 通过urllib模块获取海报二进制数据
  2. 将二进制数据流写入方式将数据写入文件中
import urllib.request as ur
from doubanmov.logmessage import clogger
# import spiders.movie as sm
class DoubanmovPipeline(object):
    def __init__(self):
        self.log = clogger.demo()
    def process_item(self, item, spider):
        try:
            #通过url获取网页数据
            res = ur.urlopen(item['pic'][0])
            #读取网页返回数据
            res = res.read()
            name = item['title'][0] + '.jpg'
            #通过基本数据存储海报存储至文件中
            with open('data/pic/{0}'.format(name),mode='wb')as file:
                file.write(res)
            self.log.logginfo('向"data/pic"中下载了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.log.loggerror('向"data/pic"中下载<<{0}>>电影失败'.format(item['title'][0]))
        return item

深度自动采集模块

  1. 获取下一页数据采集地址(movie.py)
  2. 判断下一页地址是否为空
  3. 判断是否继续翻页
  4. 通过scrapy.request和新地址回调爬去数据函数
      	#通过第一页数据源代码查找到下一页地址并获取地址
        next_di = response.xpath('//div[@class="paginator"]/span[3]/a/@href').extract()
        #将地址中的翻页具体数据提取作为日志用
        page1 = re.match(r"\?start=(.*?)&",next_di[0])
        page = math.floor(int(page1[1])/25)+1
        #判断是否为最后一页,是则为空
        if next_di:
            #判断是否继续翻页
            choose = input('是否继续翻页:(y/n)>>>')
            if choose.lower()=='y':
                self.log.logginfo('选择了继续翻页翻至第{0}页'.format(page))
                #拼接下一页的新地址
                next_page = 'https://movie.douban.com/top250' + next_di[0]
                #回调函数,递归爬虫方法
                yield scrapy.Request(next_page,callback=self.parse)
            else:
                self.log.logginfo('选择了退出')

日志系统模块

  • 方法一:
  1. 通过代用logging模块创建系统日志模块
  2. 增加日志等级的方法(info,error)
  3. 通过模块调用至所需的py文件中。
  4. 调用日志等级方法并存储日志信息
import logging
import os
import time
#创建日志系统模块
class clogger:
    a = None
    def __init__(self):
        #获取logger对象
        self.logger = logging.getLogger(__name__)
        #设置日志等级
        self.logger.setLevel(logging.INFO)
        #设置格式化输出
        logmat = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s --- %(message)s')
        #设置文件路径
        if not os.path.exists('log'):
            os.mkdir('log')
        filepath = os.path.join('log','系统日志'+'.log')

        #设置FileHandler对象
        filehand = logging.FileHandler(filepath)
        #设置级别
        filehand.setLevel(logging.INFO)
        #设置格式化输出
        filehand.setFormatter(logmat)
        #添加filehandler对象
        self.logger.addHandler(filehand)
    #定义静态方法判断是否继续创建类对象
    @staticmethod
    def demo():
        if clogger.a == None:
            clogger.a=clogger()
        return clogger.a
    def logginfo(self,mess):
        self.logger.info(mess)
        pass
    def loggerror(self,mess):
        self.logger.error(mess)
        pass
#调用创建日志模块
from doubanmov.logmessage import clogger
class DoubanmovPipeline(object):
    def __init__(self):
        self.log1 = clogger.demo()
    def process_item(self, item, spider):
        #管道输出
        try:
            print('电影排名:{0}'.format(item['rank'][0]))
            print('电影名字:<<{0}>>'.format(item['title'][0]))
            #调用日志模块的方法
            self.log1.logginfo('输出了<<{0}>>电影'.format(item['title'][0]))
        except:
            self.log1.loggerror('输出<<{0}>>电影失败'.format(item['title'][0]))
            pass
        return item
  • 方法二:
    利用Scrapy框架的日志系统存储日志(settings.py)
  1. 日志等级
    critical------严重错误
    error--------一般错误
    warning----警告信息
    info----------一般信息
    debug------调试信息
  2. 日志设置
    LOG_ENABLE ----默认:TRUE,启用logging
    LOG_FILE----------默认:None,在当前目录里创建logging输出文件名
    LOG_LEVEL--------默认:DEBUG,log的最低等级
    LOG_STDOUT-----默认:FALSE,如果为TRUE,进程将所有标准化输出重定向到log文件中
    LOG_ENCODING----默认:utf-8
LOG_ENABLED = False
LOG_FILE = 'log/aaa.log'
LOG_LEVEL = "INFO"
LOG_STDOUT = True
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值