Python学习之路-爬虫进阶:爬虫框架雏形

Python学习之路-爬虫进阶:爬虫框架雏形

代码实现分析

明确模块之间的逻辑关系

五个核心模块和三个内置的对象是关键模块,需要优先实现

先抛开中间件,分析下它们之间的逻辑关系是:

  1. 构造spider中start_urls中的请求
  2. 传递给调取器进行保存,之后从中取出
  3. 取出的request对象交给下载的进行下载,返回response
  4. response交给爬虫模块进行解析,提取结果
  5. 如果结果是request对象,重新交给调度器,如果结果是item对象,交给管道处理

以上的逻辑是在引擎中完成的

设计代码结构

  1. 首先给框架起一个名称,如:

     scrapy_plus
    
  2. 继续分类以及解耦的设计思想:

    • 把核心模块放置在一起

    • 请求对象模块和响应对象模块统一作为http模块

    • 数据对象单独作为一个分类

      代码结构如下:

      -- scrapy_plus-- __init__.py-- core-- __init__.py-- spider.py-- scheduler.py-- downloader.py-- pipeline.py-- engine.py-- http-- __init__.py-- request.py-- response.py-- item.py
      

到这里,我们完成了框架的大致结构是设计,那么接下来我们就需要实现模块中的具体内容了

request对象的封装

对HTTP基本的请求属性进行简单封装,实现一个Request对象

# scrapy/http/request.py
'''封装Request对象'''class Request(object):'''框架内置请求对象,设置请求信息'''def __init__(self, url, method='GET',\headers=None, params=None, data=None):self.url = url    # 请求地址self.method = method    # 请求方法self.headers = headers    # 请求头self.params = params    # 请求参数self.data = data    # 请求体

response对象的封装

对HTTP基本的响应属性进行简单封装,实现一个Response对象

# scrapy/http/response.py
'''封装Response对象'''class Response(object):'''框架内置Response对象'''def __init__(self, url, status_code, headers, body):self.url = url    # 响应urlself.status_code = status_code    # 响应状态码self.headers = headers    # 响应头self.body = body    # 响应体

item对象的封装

对数据进行简单封装,实现Item对象:

# scrapy/item.py
'''item对象'''class Item(object):'''框架内置Item对象'''def __init__(self, data):# data表示传入的数据self._data = data    # 设置为简单的私有属性@propertydef data(self):'''对外提供data进行访问,一定程度达到保护的作用'''return self._data

其中property的理解:

  • property 能够让调用一个方法和调用一个属性一样容易,即不用打括号
  • property 能够让这个属性的值是只读的,即不能够对其进行重新赋值,达到一定的保护的目的

spider模块的封装

爬虫组件功能

  • 构建请求信息(初始的),也就是生成请求对象(Request)
  • 解析响应对象,返回数据对象(Item)或者新的请求对象(Request)
实现方案
  • 实现start_requests方法,返回请求对象
  • 实现parse方法,返回Item对象或者新的请求对象
# scrapy_plus/core/spider.py
'''爬虫组件封装'''
from scrapy_plus.item import Item    # 导入Item对象
from scrapy_plus.http.request import Request    # 导入Request对象class Spider(object):'''1. 构建请求信息(初始的),也就是生成请求对象(Request)2. 解析响应对象,返回数据对象(Item)或者新的请求对象(Request)'''start_url = 'http://www.baidu.com'    # 默认初始请求地址   #这里以请求百度首页为例def start_requests(self):'''构建初始请求对象并返回'''return Request(self.start_url)def parse(self, response):'''解析请求并返回新的请求对象、或者数据对象'''return Item(response.body)   # 返回item对象

调度器模块的封装

调度器功能
  • 缓存请求对象(Request),并为下载器提供请求对象,实现请求的调度:
  • 对请求对象进行去重判断:实现去重方法_filter_request,该方法对内提供,因此设置为私有方法
实现方案
  • 利用队列FIFO存储请求;
  • 实现add_request方法添加请求,接收请求对象作为参数;
  • 实现get_request方法对外提供从队列取出的请求对象
# scrapy_plus/core/scheduler.py
'''调度器模块封住'''
# 利用six模块实现py2和py3兼容
from six.moves.queue import Queueclass Scheduler(object):'''1. 缓存请求对象(Request),并为下载器提供请求对象,实现请求的调度2. 对请求对象进行去重判断'''def __init__(self):self.queue = Queue()def add_request(self, request):'''添加请求对象'''self.queue.put(request)def get_request(self):'''获取一个请求对象并返回'''request = self.queue.get()return requestdef _filter_request(self):'''请求去重'''# 暂时不实现pass

下载器模块的封装

下载器功能

根据请求对象(Request),发起HTTP、HTTPS网络请求,拿到HTTP、HTTPS响应,构建响应对象(Response)并返回

实现方案
  • 利用requests、urllib2等模块发请求,这里使用requests模块
  • 实现get_response方法,接收request请求对象作为参数,发起请求,获取响应
# scrapy_plus/core/downloader.py
'''下载器组件'''
import requests
from scrapy_plus.http.response import Responseclass Downloader(object):'''根据请求对象(Request),发起HTTP、HTTPS网络请求,拿到HTTP、HTTPS响应,构建响应对象(Response)并返回'''def get_response(self, request):'''发起请求获取响应的方法'''# 1. 根据请求对象,发起请求,获取响应#    判断请求方法:if request.method.upper() == 'GET':resp = requests.get(request.url, headers=request.headers,\params=request.params)elif request.method.upper() == 'POST':resp = requests.post(request.url,headers=request.headers,\params=request.params,data=request.data)else:# 如果方法不是get或者post,抛出一个异常raise Exception("不支持的请求方法")# 2. 构建响应对象,并返回return Response(resp.url, resp.status_code, resp.headers, resp.content)

管道模块的封装

管道组件功能

负责处理数据对象

实现方案
  • 实现process_item方法,接收数据对象作为参数
# scrapy_plus/core/pipeline.py
'''管道组件封装'''class Pipeline(object):'''负责处理数据对象(Item)'''def process_item(self, item):'''处理item对象'''print("item: ", item)

引擎模块的封装

引擎组件功能
  • 对外提供整个的程序的入口
  • 依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)
实现方案
  • 利用init方法初始化其他组件对象,在内部使用
  • 实现start方法,由外部调用,启动引擎
  • 实现_start_engine方法,完成整个框架的运行逻辑
  • 具体参考上一小节中雏形结构引擎的逻辑
# scrapy_plus/core/engine.py
'''引擎组件'''
from scrapy_plus.http.request import Request    # 导入Request对象from .scheduler import Scheduler
from .downloader import Downloader
from .pipeline import Pipeline
from .spider import Spiderclass Engine(object):'''a. 对外提供整个的程序的入口b. 依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)'''def __init__(self):self.spider = spider()    # 接收爬虫对象self.scheduler = Scheduler()    # 初始化调度器对象self.downloader = Downloader()    # 初始化下载器对象self.pipeline = Pipeline()    # 初始化管道对象def start(self):'''启动整个引擎'''self._start_engine()def _start_engine(self):'''依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)'''# 1. 爬虫模块发出初始请求start_request = self.spider.start_requests()# 2. 把初始请求添加给调度器self.scheduler.add_request(start_request)# 3. 从调度器获取请求对象,交给下载器发起请求,获取一个响应对象request = self.scheduler.get_request()# 4. 利用下载器发起请求response = self.downloader.get_response(request)# 5. 利用爬虫的解析响应的方法,处理响应,得到结果result = self.spider.parse(response)# 6. 判断结果对象# 6.1 如果是请求对象,那么就再交给调度器if isinstance(result, Request):self.scheduler.add_request(result)# 6.2 否则,就交给管道处理else:self.pipeline.process_item(result)

实现中间件模块

为什么需要中间件

中间件相当于一个钩子,能够在其中对request对象和response响应根据特定的需求进行一些特定的处理 例如:对于所有的request对象,我们需要在其中对他添加代理或者是随机的User-Agent都可以在中间件中完成

完成爬虫中间件spider_middlewares

# scrapy_plus/middlewares/spider_middlewares.py
class SpiderMiddleware(object):'''爬虫中间件基类'''def process_request(self, request):'''预处理请求对象'''print("这是爬虫中间件:process_request方法")return requestdef process_response(self, response):'''预处理数据对象'''print("这是爬虫中间件:process_response方法")return response

完成下载downloader_middlewares

# scrapy_plus/middlewares/downloader_middlewares.py
class DownloaderMiddleware(object):'''下载器中间件基类'''def process_request(self, request):'''预处理请求对象'''print("这是下载器中间件:process_request方法")return requestdef process_response(self, response):'''预处理响应对象'''print("这是下载器中间件:process_response方法")return response

修改engine.py

加入中间件模块

# scrapy_plus/core/engine.py
'''引擎
a. 对外提供整个的程序的入口
b. 依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)
'''
from scrapy_plus.http.request import Request    # 导入Request对象
from scrapy_plus.middlewares.spider_middlewares import SpiderMiddleware
from scrapy_plus.middlewares.downloader_middlewares import DownloaderMiddlewarefrom .spider import Spider
from .scheduler import Scheduler
from .downloader import Downloader
from .pipeline import Pipelineclass Engine(object):def __init__(self):......self.spider_mid = SpiderMiddleware()    # 初始化爬虫中间件对象self.downloader_mid = DownloaderMiddleware()    # 初始化下载器中间件对象......def _start_engine(self):'''依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)'''# 1. 爬虫模块发出初始请求start_request = self.spider.start_requests()# 2. 把初始请求添加给调度器# 利用爬虫中间件预处理请求对象start_request = self.spider_mid.process_request(start_request)self.scheduler.add_request(start_request)# 3. 从调度器获取请求对象,交给下载器发起请求,获取一个响应对象request = self.scheduler.get_request()# 利用下载器中间件预处理请求对象request = self.downloader_mid.process_request(request)# 4. 利用下载器发起请求response = self.downloader.get_response(request)# 利用下载器中间件预处理响应对象response = self.downloader_mid.process_response(response)# 5. 利用爬虫的解析响应的方法,处理响应,得到结果result = self.spider.parse(response)# 6. 判断结果对象# 6.1 如果是请求对象,那么就再交给调度器if isinstance(result, Request):# 利用爬虫中间件预处理请求对象result = self.spider_mid.process_request(result)self.scheduler.add_request(result)# 6.2 否则,就交给管道处理else:self.pipeline.process_item(result)

观察结果

运行main.py文件,查看结果

运行结果:

这是爬虫中间件:process_request方法
这是下载器中间件:process_request方法
这是下载器中间件:process_request方法
这是爬虫中间件:process_response方法
item对象: <scrapy_plus.item.Item object at 0x10759eef0>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/684141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Json-序列化字符串时间格式问题

序列化字符串时间格式问题 一、项目场景二、问题描述三、解决方案 一、项目场景 最近C#中需要将实体进行json序列化&#xff0c;使用了Newtonsoft.Json public static void TestJson(){DataTable dt new DataTable();dt.Columns.Add("Age", Type.GetType("Sys…

java8使用流

这种处理数据的方式很有用&#xff0c;因为你让Stream API管理如何处理数据。这样StreamAPI就可以在背后进行多种优化。此外&#xff0c;使用内部迭代的话&#xff0c;SteamAPI可以决定并行运行你的代码。这要是用外部迭代的话就办不到了&#xff0c;因为你只能用单一线程挨个迭…

天空之眼的观后感

天空之眼&#xff0c;一部反恐题材的电影。 原名eye in the sky&#xff0c;从一个不一样的视角来讲反恐的故事。 这里不提故事本身&#xff0c;知乎&#xff0c;豆瓣上有很多分享。 最初我是在公司组织的培训交流上看到这部电影的剪辑&#xff0c;当时仅作为培训的开始前的导入…

VMwareWorkstation17.0虚拟机安装Windows2.03

VMwareWorkstation17.0虚拟机安装Windows2.03 第一篇 下载Windows2.03第二篇 配置Windows2.03虚拟机机器环境第三篇 启动Windows2.03系统 第一篇 下载Windows2.03 1.Windows2.0原版软盘下载地址是 暂不提供&#xff0c;后续更新 2.Windows2.03虚拟机镜像下载地址是 Windows2…

STM32物联网(ESP-01S模块及STM32和ESP-01S通信方式介绍)

文章目录 前言一、ESP-01S模块介绍二、STM32和ESP-01S通信方式介绍三、什么是AT指令四、创建基础工程总结 前言 本篇文章我们开始正式进入STM32物联网的专栏&#xff0c;在这个专栏中将会带大家学习使用STM32进行联网&#xff0c;联网模块的话主要就是使用到了ESP-01S WIFI模块…

【深度学习】S2 数学基础 P5 自动微分

目录 自动微分 Autograd一元函数自动微分案例 自动微分 Autograd 深度学习框架&#xff0c;因为存在自动微分技术&#xff0c;可以自动计算梯度&#xff0c;这极大地提升了训练复杂神经网络模型的效率。从而无需繁琐的手动计算&#xff0c;避免错误的发生。 自动微分的核心原…

『运维备忘录』之 Zip 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

Java学习22--接口类

接口类的定义和实现 Java接口&#xff08;Interface&#xff09;是Java编程语言中的一个非常重要的概念。它是一个完全抽象的类&#xff0c;用于定义一组方法&#xff0c;这些方法由类来实现。接口定义了一个契约&#xff0c;即规定了类应该具备哪些方法&#xff0c;但并不实现…

WebStorm | 如何修改webstorm中新建html文件默认生成模板中title的初始值

在近期的JS的学习中&#xff0c;使用webstorm&#xff0c;总是要先新建一个html文件&#xff0c;然后再到里面书写<script>标签&#xff0c;真是麻烦&#xff0c;而且标题也是默认的title&#xff0c;想改成文件名还总是需要手动去改 经过小小的研究&#xff0c;找到了修…

单片机学习笔记---LCD1602

LCD1602介绍 LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是一种字符型液晶显示模块&#xff0c;可以显示ASCII码的标准字符和其它的一些内置特殊字符&#xff08;比如日文的片假名&#xff09;&#xff0c;还可以有8个自定义字符 显示容量&#xff1a;…

centos7.9 搭建k8s

K3s -轻量级Kubernetes K3s 是轻量级的 Kubernetes。K3s 易于安装&#xff0c;仅需要 Kubernetes 内存的一半&#xff0c;所有组件都在一个小于 100 MB 的二进制文件中。 为什么叫 K3s? 我们希望安装的 Kubernetes 只占用一半的内存。Kubernetes 是一个 10 个字母的单词&am…

【AIGC】Stable Diffusion安装包

Stable Diffusion 的安装教程通常分为以下几个步骤&#xff1a; 一、安装 Python&#xff1a; 确保您的系统中已经安装了 Python&#xff0c;并且版本符合 Stable Diffusion 的要求。通常情况下&#xff0c;Python 版本应为 3.6 或更高版本。您可以从 Python 官方网站下载并安…

AlmaLinux更换鼠标样式为Windows样式

文章目录 前言先看看条件与依赖第一步&#xff1a;测试最终效果第二步&#xff1a;使用CursorXP修改鼠标样式CurosrXP安装CursorXP使用 第三步&#xff1a;Linux端环境搭建与命令执行UbuntuFedora其他系统均失败 第四步&#xff1a;应用主题 前言 只不过是突发奇想&#xff0c…

React:高阶组件|ref转发

高阶组件 参考文档&#xff1a;高阶组件 – React (reactjs.org) 高阶组件&#xff08;Higher-Order Components&#xff0c;简称 HOC&#xff09;是React中用于复用组件逻辑的一种高级技巧。具体而言&#xff1a;高阶组件是参数为组件&#xff0c;返回值为新组件的函数。 组件…

vue3 codemirror yaml文件编辑器插件

需求&#xff1a;前端编写yaml配置文件 &#xff0c;检查yaml语法 提供语法高亮 。 默认内容从后端接口获取 显示在前端 &#xff0c; 前端在codemirror 插件中修改文件内容 &#xff0c;并提交修改 后端将提交的内容写入服务器配置文件中 。 codemirror 通过ref 后期编辑器…

jacob使用教程---环境搭建及基本组成元素

参考资料: jacob的GitHub地址 jacob官网(个人感觉不重要) microsoft官方VBA文档(很重要,jacob所有的参数都来自于这里) jacob找COM组件 jacob环境配置教程 jacob将word转为各种格式 提取word中审阅内容 本人参考例子及相关资料 具有参考价值的博客 jacob操作e…

2024 前端面试题 附录3

这里记录的是昨天和今天原篇的知识点补充 原篇地址&#xff1a; 2024 前端面试题&#xff08;GPT回答 示例代码 解释&#xff09;No.41 - No.60 2024 前端面试题&#xff08;GPT回答 示例代码 解释&#xff09;No.61 - No.100 2024 前端面试题&#xff08;GPT回答 示例代…

【Python】通过conda安装Python的IDE

背景 系统&#xff1a;win11 软件&#xff1a;anaconda Navigator 问题现象&#xff1a;①使用Navigator安装jupyter notebook以及Spyder IDE 一直转圈。②然后进入anaconda prompt执行conda install jupyter notebook一直卡在Solving environment/-\。 类似问题&#xff1a; …

【Java基础题型】逢7过

朋友聚会的时候可能会玩一个游戏&#xff1a;缝7过 游戏规则&#xff1a;从任意一个数字开始报数&#xff0c;当你要报的数字是包含7或者 是7的倍数时&#xff0c;都要说&#xff1a;"过" 需求&#xff1a;使用程序在控制台打印出1-100之间的满足逢七必过规则的数…

计算机网络——12DNS

DNS DNS的必要性 IP地址标识主机、路由器但IP地址不好记忆&#xff0c;不便于人类用使用&#xff08;没有意义&#xff09;人类一般倾向于使用一些有意义的字符串来标识Internet上的设备存在着“字符串”——IP地址的转换的必要性人类用户提供要访问机器的“字符串”名称由DN…