python实现scrapy爬虫每天定时抓取数据的示例代码


Posted in Python onJanuary 27, 2021

1. 前言。

1.1. 需求背景。

  •  每天抓取的是同一份商品的数据,用来做趋势分析。
  • 要求每天都需要抓一份,也仅限抓取一份数据。
  • 但是整个爬取数据的过程在时间上并不确定,受本地网络,代理速度,抓取数据量有关,一般情况下在20小时左右,极少情况下会超过24小时。

1.2. 实现功能。

通过以下三步,保证爬虫能自动隔天抓取数据:
每天凌晨00:01启动监控脚本,监控爬虫的运行状态,一旦爬虫进入空闲状态,启动爬虫。

一旦爬虫执行完毕,自动退出脚本,结束今天的任务。

一旦脚本距离启动时间超过24小时,自动退出脚本,等待第二天的监控脚本启动,重复这三步。

2. 环境。

python 3.6.1

系统:win7

IDE:pycharm

安装过scrapy

3. 设计思路。

3.1. 前提:

目前爬虫是通过scrapy模块自带的cmdline.execute来启动的。

from scrapy import cmdline
cmdline.execute('scrapy crawl mySpider'.split())

3.2. 将自动执行脚本做到scrapy爬虫的外部

(1)每天凌晨00:01启动脚本(控制脚本的存活时间为24小时),监测爬虫的运行状态(需要用一个标记信息来表示爬虫的状态:运行还是停止)。

  • 如果爬虫处于运行状态(前一天爬取数据尚未结束),进入第(2)步;
  • 如果爬虫处于非运行状态(前一天的爬取任务已完成,今天的尚未开始),进入第(3)步;

(2)脚本进入等待阶段,每隔10分钟,检查一下爬虫的运行状态,如(1)。但是一旦发现,脚本的等待时间超过了24小时,则自动退出脚本,因为第二天的监测脚本已经开始运行了,接替了它的任务。

(3)做一些爬虫启动前的准备工作(删除用来续爬的文件,防止爬虫不运行了),启动爬虫爬取数据,待爬虫正常结束后,退出脚本,完成当天的爬取任务。

4. 准备工作。

4.1. 标记爬虫的运行状态。

通过判断文件是否存在的方式来判断爬虫是否处于运行状态:

  • 在爬虫启动时,创建一个isRunning.txt文件。
  • 在爬虫结束时,删除这个isRunning.txt文件。

那么isRunning.txt存在,就说明爬虫正在运行;文件不存在,就说明爬虫不在运行。

# 文件pipelines.py
# 爬虫启动时
checkFile = "isRunning.txt"
class myPipeline:
  def open_spider(self, spider):
    self.client = MongoClient('localhost:27017') # 连接Mongodb
    self.db = self.client['mydata']        # 待存储数据的数据库mydata
    f = open(checkFile, "w")     # 创建一个文件,代表爬虫在运行中
    f.close()
# 文件pipelines.py
# 爬虫正常结束时
checkFile = "isRunning.txt"
class myPipeline:
  def close_spider(self, spider):
    self.client.close()
    isFileExsit = os.path.isfile(checkFile)
    if isFileExsit:
      os.remove(checkFile)

4.2. 爬虫支持续爬,能随时暂停,方便调试。

# 在scrapy项目中添加start.py文件,用于启动爬虫
from scrapy import cmdline
# 在爬虫运行过程中,会自动将状态信息存储在crawls/storeMyRequest目录下,支持续爬
cmdline.execute('scrapy crawl mySpider -s JOBDIR=crawls/storeMyRequest'.split())
# Note:若想支持续爬,在ctrl+c终止爬虫时,只能按一次,爬虫在终止时需要进行善后工作,切勿连续多次按ctrl+c

python实现scrapy爬虫每天定时抓取数据的示例代码

4.3. Log按照每天的日期命名,方便查看和调试

设置Log等级:

# 文件mySpider.py
class mySpider(CrawlSpider):
  name = "mySpider"
  allowed_domains = ['http://photo.poco.cn/']
  custom_settings = {
    'LOG_LEVEL':'INFO', # 减少Log输出量,仅保留必要的信息
    # ...... 在爬虫内部用custom_setting可以让这个配置信息仅对这一个爬虫生效
  }

以日期为Log文件命名

# 文件settings.py
import datetime
BOT_NAME = 'mySpider'
ROBOTSTXT_OBEY = False
startDate = datetime.datetime.now().strftime('%Y%m%d')
LOG_FILE=f"mySpiderlog{startDate}.txt"

4.4. 为数据按日期存储到不同的表(mongodb的集合)中

# 文件pipelines.py
import datetime
GALANCE=f'galance{datetime.datetime.now().strftime("%Y%m%d")}' # 表名
class myPipeline:
  def open_spider(self, spider):
    self.client = MongoClient('localhost:27017') # 连接Mongodb
    self.db = self.client['mydata']        # 待存储数据的数据库mydata
self.db[GALANCE].insert(dict(item))

python实现scrapy爬虫每天定时抓取数据的示例代码

4.5. 编写批处理文件启动爬虫

# 文件run.bat
cd /d F:/newClawer20170831/mySpider
call python main.py
pause

python实现scrapy爬虫每天定时抓取数据的示例代码

5. 实现代码

5.1. 编写python脚本

# 文件timerStartDaily.py
from scrapy import cmdline
import datetime
import time
import shutil
import os

recoderDir = r"crawls"  # 这是为了爬虫能够续爬而创建的目录,存储续爬需要的数据
checkFile = "isRunning.txt" # 爬虫是否在运行的标志

startTime = datetime.datetime.now()
print(f"startTime = {startTime}")

i = 0
miniter = 0
while True:
  isRunning = os.path.isfile(checkFile)
  if not isRunning:            # 爬虫不在执行,开始启动爬虫
    # 在爬虫启动之前处理一些事情,清掉JOBDIR = crawls
    isExsit = os.path.isdir(recoderDir) # 检查JOBDIR目录crawls是否存在
    print(f"mySpider not running, ready to start. isExsit:{isExsit}")
    if isExsit:
      removeRes = shutil.rmtree(recoderDir) # 删除续爬目录crawls及目录下所有文件
      print(f"At time:{datetime.datetime.now()}, delete res:{removeRes}")
    else:
      print(f"At time:{datetime.datetime.now()}, Dir:{recoderDir} is not exsit.")
    time.sleep(20)
    clawerTime = datetime.datetime.now()
    waitTime = clawerTime - startTime
    print(f"At time:{clawerTime}, start clawer: mySpider !!!, waitTime:{waitTime}")
    cmdline.execute('scrapy crawl mySpider -s JOBDIR=crawls/storeMyRequest'.split())
    break #爬虫结束之后,退出脚本
  else:
    print(f"At time:{datetime.datetime.now()}, mySpider is running, sleep to wait.")
  i += 1
  time.sleep(600)    # 每10分钟检查一次
  miniter += 10
  if miniter >= 1440:  # 等待满24小时,自动退出监控脚本
    break

5.2. 编写bat批处理文件

# 文件runTimerRunDaily.bat
cd /d F:/newClawer20170831/mySpider
call python timerStartDaily.py
pause

6. 部署。

6.1. 添加计划任务。

参考以下这篇博客部署windows计划任务:

有关windows计划任务相关设置的详细说明如下:

https://technet.microsoft.com/zh-cn/library/cc722178.aspx

6.2. 注意事项。

(1)在添加计划任务时,要按照如下图进行勾选(只在用户登录时运行),才能弹出下面的cmd任务界面,方便观察和调试。

python实现scrapy爬虫每天定时抓取数据的示例代码 

python实现scrapy爬虫每天定时抓取数据的示例代码

(2)由于爬虫运行时间很长,如果按照默认设置,在凌晨运行实例时,上一次启动尚未结束,会导致这次启动失败,所以要更改默认设置为(如果此任务已经运行:并行运行新实例。保护机制在于每个启动脚本在等待24小时候会自动退出,来保证不会重复启动)。

python实现scrapy爬虫每天定时抓取数据的示例代码

(3)如果想支持续传,只能按一次 ctrl + c 来停止爬虫运行。因为终止爬虫时,爬虫需要做一些善后工作,如果连续按多次ctrl + c来停止爬虫,爬虫将来不及善后,会导致无法续爬。 6.3. 效果展示。

正常执行完成:

python实现scrapy爬虫每天定时抓取数据的示例代码

正在执行中:

python实现scrapy爬虫每天定时抓取数据的示例代码

到此这篇关于python实现scrapy爬虫每天定时抓取数据的示例代码的文章就介绍到这了,更多相关python scrapy定时抓取内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中逗号的三种作用实例分析
Jun 08 Python
Python基于pygame实现图片代替鼠标移动效果
Nov 11 Python
Python实现简易Web爬虫详解
Jan 03 Python
Python XML转Json之XML2Dict的使用方法
Jan 15 Python
django 消息框架 message使用详解
Jul 22 Python
一行Python代码过滤标点符号等特殊字符
Aug 12 Python
python打开使用的方法
Sep 30 Python
Django多数据库配置及逆向生成model教程
Mar 28 Python
如何把外网python虚拟环境迁移到内网
May 18 Python
无惧面试,带你搞懂python 装饰器
Aug 17 Python
pytorch 梯度NAN异常值的解决方案
Jun 05 Python
Python中的datetime包与time包包和模块详情
Feb 28 Python
使用bandit对目标python代码进行安全函数扫描的案例分析
Jan 27 #Python
用Python实现定时备份Mongodb数据并上传到FTP服务器
Jan 27 #Python
python re.match()用法相关示例
Jan 27 #Python
selenium+python实现基本自动化测试的示例代码
Jan 27 #Python
Python开发.exe小工具的详细步骤
Jan 27 #Python
Python中正则表达式对单个字符,多个字符和匹配边界等使用
Jan 27 #Python
python正则表达式re.match()匹配多个字符方法的实现
Jan 27 #Python
You might like
discuz7 phpMysql操作类
2009/06/21 PHP
Wordpress 相册插件 NextGEN-Gallery 添加目录将中文转为拼音的解决办法
2010/12/29 PHP
flash用php连接数据库的代码
2011/04/21 PHP
解析PHP 5.5 新特性
2013/07/02 PHP
Yii查询生成器(Query Builder)用法实例教程
2014/09/04 PHP
php跨服务器访问方法小结
2015/05/12 PHP
Docker配置PHP开发环境教程
2016/12/21 PHP
jsp js鼠标移动到指定区域显示选项卡离开时隐藏示例
2013/06/14 Javascript
jQuery遍历页面所有CheckBox查看是否被选中的方法
2015/04/14 Javascript
JavaScript淡入淡出渐变简单实例
2015/08/06 Javascript
JavaScript正则表达式的分组匹配详解
2016/02/13 Javascript
详解vue2路由vue-router配置(懒加载)
2017/04/08 Javascript
Webpack实现按需打包Lodash的几种方法详解
2017/05/08 Javascript
简单的网页广告特效实例
2017/08/19 Javascript
详解vuex结合localstorage动态监听storage的变化
2018/05/03 Javascript
vue 路由嵌套高亮问题的解决方法
2018/05/17 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
vue路由事件beforeRouteLeave及组件内定时器的清除方法
2018/09/29 Javascript
使用vuepress搭建静态博客的示例代码
2019/02/14 Javascript
Openlayers实现扩散的动态点(水纹效果)
2020/08/17 Javascript
Python 详解基本语法_函数_返回值
2017/01/22 Python
利用python实现简单的邮件发送客户端示例
2017/12/23 Python
Python 元类实例解析
2018/04/04 Python
Python使用pyautocad+openpyxl处理cad文件示例
2019/07/11 Python
Python IDE Pycharm中的快捷键列表用法
2019/08/08 Python
升级keras解决load_weights()中的未定义skip_mismatch关键字问题
2020/06/12 Python
荷兰网上买鞋:MooieSchoenen.nl
2017/09/12 全球购物
介绍一下write命令
2014/08/10 面试题
共产党员公开承诺书范文
2014/03/28 职场文书
高三学生评语大全
2014/04/25 职场文书
春秋淹城导游词
2015/02/11 职场文书
清洁工岗位职责
2015/02/13 职场文书
机修车间主任岗位职责
2015/04/08 职场文书
Mysql数据库表中为什么有索引却没有提高查询速度
2022/02/24 MySQL
【DOTA2】当街暴打?PSG LGD vs VG - DPC 2022 WINTER TOUR CN
2022/04/02 DOTA
python数字图像处理之图像自动阈值分割示例
2022/06/28 Python