自学Python第二十九天-feapder框架创建爬虫

news2024/11/15 23:49:21

自学Python第二十九天-feapder框架创建爬虫

  • 安装
  • `feapder` 的设计架构
  • `feapder` 框架的简单使用
    • 简单创建爬虫
    • 简单爬取数据
    • 简单的数据保存
  • 中间件
  • 校验
  • 浏览器渲染
    • 使用浏览器渲染获取接口数据

feapder是一款上手简单,功能强大的 Python爬虫框架,内置 AirSpiderSpiderTaskSpiderBatchSpider四种爬虫解决不同场景的需求。支持断点续爬、监控报警、浏览器渲染、海量数据去重等功能。更有功能强大的爬虫管理系统 feaplat为其提供方便的部署及调度。

feapder 设计思路类似于 scrapy,不过它是国人开发的框架工具,官方文档是中文的,查询比较方便,使用门槛比较低。

官方文档

安装

feapder 需要 python 3.6 以上,且需要依赖特定版的 selenium 等依赖包,所以最好创建单独虚拟环境。另外它有三个版本,区别在于:

  • 精简版:不支持浏览器渲染、不支持基于内存去重、不支持入库mongo
pip install feapder
  • 浏览器渲染版:不支持基于内存去重、不支持入库mongo
pip install "feapder[render]"
  • 完整版:支持所有功能(常用选择)
pip install "feapder[all]"

安装完成后,可以在控制台执行查看是否安装成功

feapder

此时有可能会提示警告:

NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'

这是因为 feapder 建议使用 urllib3 v1 版本。所以最好降级一下

pip install urllib3=1.26.18

feapder 的设计架构

在这里插入图片描述

模块名称模块功能
spider框架调度核心
parser_control模版控制器负责调度parser
collector任务收集器负责从任务队里中批量取任务到内存,以减少爬虫对任务队列数据库的访问频率及并发量
parser数据解析器
start_request初始任务下发函数
item_buffer数据缓冲队列批量将数据存储到数据库中
request_buffer请求任务缓冲队列批量将请求任务存储到任务队列中
request数据下载器封装了requests,用于从互联网上下载数据
response请求响应封装了response, 支持xpathcssre等解析方式,自动处理中文乱码

feapder 的执行流程为

  1. spider调度 start_request 生产任务
  2. start_request 下发任务到request_buffer
  3. spider调度 request_buffer 批量将任务存储到任务队列数据库中
  4. spider调度 collector 从任务队列中批量获取任务到内存队列
  5. spider调度 parser_controlcollector的内存队列中获取任务
  6. parser_control 调度 request 请求数据
  7. request 请求与下载数据
  8. request将下载后的数据给 response ,进一步封装
  9. 将封装好的 response 返回给 parser_control (图示为多个parser_control,表示多线程)
  10. parser_control调度对应的 parser ,解析返回的response(图示多组parser表示不同的网站解析器)
  11. parser_controlparser解析到的数据item及新产生的request分发到 item_bufferrequest_buffer
  12. spider调度 item_bufferrequest_buffer 将数据批量入库

feapder 框架的简单使用

简单创建爬虫

首先创建爬虫,以豆瓣为例:

feapder create -s douban

执行命令后需要手动选择对应的爬虫模板,模板功能如下:

  • AirSpider 轻量爬虫:学习成本低,可快速上手
  • Spider 分布式爬虫:支持断点续爬、爬虫报警、数据自动入库等功能
  • TaskSpider分布式爬虫:内部封装了取种子任务的逻辑,内置支持从redis或者mysql获取任务,也可通过自定义实现从其他来源获取任务
  • BatchSpider 批次爬虫:可周期性的采集数据,自动将数据按照指定的采集周期划分。(如每7天全量更新一次商品销量的需求)

命令执行成功后选择AirSpider模板。默认生成的代码继承了feapder.AirSpider,包含 start_requestsparser 两个函数,含义如下:

  1. feapder.AirSpider:轻量爬虫基类
  2. start_requests:初始任务下发入口
  3. feapder.Request:基于requests库类似,表示一个请求,支持requests所有参数,同时也可携带些自定义的参数,详情可参考Request
  4. parse:数据解析函数
  5. response:请求响应的返回体,支持xpathrecss等解析方式,详情可参考Response

除了start_requestsparser两个函数。系统还内置了下载中间件等函数,具体支持可参考BaseParser

简单爬取数据

feapder 创建了一个默认示例,是可以直接执行的,并且类似于请求头之类的也是默认设置过的(随机)。feapder 的实际使用方法和 scrapy 很类似。不过 feapder 传递数据更加方便。

import feapder


class Douban(feapder.AirSpider):
    def start_requests(self):
        for page in range(10):
            yield feapder.Request(f"https://movie.douban.com/top250?start={page * 25}&filter=")

    def parse(self, request, response):
        li_list = response.xpath('//ol/li/div[@class="item"]')
        for li in li_list:
            item = dict()
            item['title'] = li.xpath('./div[@class="info"]/div/a/span[1]/text()').extract_first()
            item['detail_url'] = li.xpath('./div[@class="info"]/div/a/@href').extract_first()
            item['score'] = li.xpath('.//div[@class="star"]/span[2]/text()').extract_first()
            # 可以将自定义变量添加到 request 中,例如 item
            yield feapder.Request(item['detail_url'], callback=self.parse_detail, item=item)

    def parse_detail(self, request, response):
        if response.xpath('//div[@class="indent"]/span[@class="all hidden"]//text()'):
            request.item['detail_text'] = response.xpath(
                '//div[@class="indent"]/span[@class="all hidden"]//text()').extract_first().strip()
        else:
            request.item['detail_text'] = response.xpath(
                '//div[@class="indent"]/span[1]//text()').extract_first().strip()
        print(request.item)


if __name__ == "__main__":
    # 开启五个线程完成爬虫任务
    Douban(thread_count=5).start()

简单的数据保存

feapder 封装好了多种支持的数据库保存方式,只需要设置一下就可以直接保存使用,而不需要手写数据保存逻辑,注意数据库中的表和字段等需要提前创建。

数据库中创建表:

from feapder.db.mysqldb import MysqlDB

db = MysqlDB(ip='localhost', port=3306, user_name='root', user_pass='root', db='py_spider')
sql = """
    create table if not exists douban_feapder(
        id int primary key auto_increment,
        title varchar(255) not null,
        score varchar(255) not null,
        detail_url varchar(255) not null,
        detail_text text
    );
"""
db.execute(sql)

# insert ignore: 数据插入,如果数据重复则忽略,例如id重复
insert_sql = """
    insert ignore into douban_feapder (id, title, score, detail_url, detail_text) values (
        0, '测试数据', 10, 'https://www.baidu.com', '测试数据'
    );
"""
db.add(insert_sql)

创建全局设置文件:

feapder create --setting

然后在 settings.py 文件中配置数据库,例如 mysql:

# MYSQL
MYSQL_IP = "localhost"
MYSQL_PORT = 3306
MYSQL_DB = "py_spider"
MYSQL_USER_NAME = "root"
MYSQL_USER_PASS = "root"

或者在爬虫中自定义局部配置

import feapder

class Douban(feapder.AirSpider):
	__custom_setting__ = dict(
		MYSQL_IP="localhost",
		MYSQL_PORT= 3306,
		MYSQL_DB="py_spider",
		MYSQL_USER_NAME="root",
		MYSQL_USER_PASS="root",
	)

然后创建 item 文件,item 的字段名是根据数据库的字段名自动生成的

# 在创建items文件之前必须确保文件名与数据库已存在的表名一致
feapder create -i douban_feapder

最后,在爬虫中,将字典类型替换为 item 类型用于数据校验,并直接 yield 此类型的数据,就可以自动入库了。

import feapder
from douban_feapder_item import DoubanFeapderItem

class Douban(feapder.AirSpider):
    def start_requests(self):
        for page in range(11):
            yield feapder.Request(f"https://movie.douban.com/top250?start={page * 25}&filter=")

    def parse(self, request, response):
        li_list = response.xpath('//ol/li/div[@class="item"]')
        for li in li_list:
            # 将字典类型替换成DoubanFeapderItem用于数据校验
            item = DoubanFeapderItem()
            item['title'] = li.xpath('./div[@class="info"]/div/a/span[1]/text()').extract_first()
            item['detail_url'] = li.xpath('./div[@class="info"]/div/a/@href').extract_first()
            item['score'] = li.xpath('.//div[@class="star"]/span[2]/text()').extract_first()
            yield feapder.Request(item['detail_url'], callback=self.parse_detail, item=item)

    def parse_detail(self, request, response):
        if response.xpath('//div[@class="indent"]/span[@class="all hidden"]//text()'):
            request.item['detail_text'] = response.xpath(
                '//div[@class="indent"]/span[@class="all hidden"]//text()').extract_first().strip()
        else:
            request.item['detail_text'] = response.xpath(
                '//div[@class="indent"]/span[1]//text()').extract_first().strip()

        # 执行yield会将解析好的数据保存到数据库中
        yield request.item

if __name__ == "__main__":
    Douban().start()

中间件

feapder 中间件只有下载中间件,没有爬虫中间件。并且中间件只是类的一个方法而已,不需要另写一个 py 文件。默认的中间件是 download_midware() 方法,除了可以重写此方法外,还可以自定义下载中间件:使用 Request 对象的 download_midware 参数指定自建创建的中间件方法名

import feapder

class Douban(feapder.AirSpider):
    def start_requests(self):
        for page in range(11):
            yield feapder.Request(f"https://movie.douban.com/top250?start={page * 25}&filter=",
            						download_midware=self.custom_download_midware)

    # 默认的下载中间件
    def download_midware(self, request):
        request.headers = {
            'User-Agent': 'abc'
        }
        request.proxies = {
            "http": "http://127.0.0.1:7890"
        }
        return request
    
    # 自定义下载中间件
    def custom_download_midware(self, request):
        request.headers = {
            'User-Agent': '123'
        }
        return request

if __name__ == "__main__":
    Douban().start()

需要注意的是,不同于 scrapy 每个请求或响应都会经过所有的中间件处理,feapder 的请求 (feapder 的中间件不处理响应) 只使用一个中间件进行处理。

校验

由于 feapder 的中间件不处理响应对象,所以 feapder 专门有个处理响应的方法,就是 validate() (校验) 方法。此方法用来检验返回的数据是否正常,可以通过 request.callback_name 来区分不同的回调解析函数,编写不同的校验逻辑。

另外当返回值为 TrueNone 时,进入解析函数;当返回值为 False 时,抛弃响应;当抛出异常时,重试请求(默认最大重试次数100次,也可以引入配置文件或自定义配置进行修改)。另外如果解析函数抛出异常也会进行重试。

class Douban(feapder.AirSpider):
	def start_requests(self):
		pass

	def parse(self, request, response):
		pass

	def validate(self, request, response):
		print('响应状态码:' response.status_code)
		if response.status_code != 200:
			raise Exception('状态码异常')		# 请求重试

if __name__ == "__main__":
    Douban().start()

浏览器渲染

feapder 框架包含了浏览器渲染功能,使用 selenium 渲染动态页面,获取渲染后的页面数据。框架内置一个浏览器渲染池,默认的池大小为1,请求时重复利用浏览器实例,只有当代理失效请求异常时,才会销毁、创建一个新的浏览器实例。

使用时,在 start_requests() 方法中,yieldfeapder.Request 对象的参数中添加 render=True 即可。如需要也可以自定义浏览器渲染配置:

# 在setting.py中有以下代码配置

# 浏览器渲染
WEBDRIVER = dict(
    pool_size=1,  # 浏览器的数量
    load_images=True,  # 是否加载图片
    user_agent=None,  # 字符串 或 无参函数,返回值为user_agent
    proxy=None,  # xxx.xxx.xxx.xxx:xxxx 或 无参函数,返回值为代理地址
    headless=False,  # 是否为无头浏览器
    driver_type="CHROME",  # CHROME、EDGE、PHANTOMJS、FIREFOX
    timeout=30,  # 请求超时时间
    window_size=(1024, 800),  # 窗口大小
    executable_path=None,  # 浏览器路径,默认为默认路径
    render_time=0,  # 渲染时长,即打开网页等待指定时间后再获取源码
    custom_argument=[
        "--ignore-certificate-errors",
        "--disable-blink-features=AutomationControlled",
    ],  # 自定义浏览器渲染参数
    xhr_url_regexes=None,  # 拦截xhr接口,支持正则,数组类型
    auto_install_driver=True,  # 自动下载浏览器驱动 支持chrome 和 firefox
    download_path=None,  # 下载文件的路径
    use_stealth_js=False,  # 使用stealth.min.js隐藏浏览器特征
)

可以在解析函数中,使用 selenium 来进行交互和获取数据

import feapder
from selenium.webdriver.common.by import By
from feapder.utils.webdriver import WebDriver


class Baidu(feapder.AirSpider):
    def start_requests(self):
        yield feapder.Request("https://www.baidu.com", render=True)

    def parse(self, request, response):
        browser: WebDriver = response.browser
        browser.find_element(By.ID, 'kw').send_keys('feapder')
        browser.find_element(By.ID, 'su').click()


if __name__ == "__main__":
    Baidu().start()

使用浏览器渲染获取接口数据

浏览器打开页面后,可能会通过访问接口获取需要渲染的数据。 feapder 可以直接获取接口数据(因为渲染后可能数据会有变化或编码、加密等)

首先在 setting.py 写入接口的正则,以便拦截动态接口数据

WEBDRIVER = dict(
	...
	xhr_url_regexes=[
		'/ad',
		'接口1正则',
		'接口2正则',
	]
)

这样只要接口符合正则,就会被拦截到。然后可以提取数据

browser: WebDriver = response.browser
# 提取文本
text = browser.xhr_text("接口1正则")
# 提取json
data = browser.xhr_json("接口2正则")
# 获取响应对象
xhr_response = browser.xhr_response('/ad')
print("请求接口", xhr_response.request.url)
print("请求头", xhr_response.request.headers)
print("请求体", xhr_response.request.data)
print("返回头", xhr_response.headers)
print("返回地址", xhr_response.url)
print("返回内容", xhr_response.content

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

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

相关文章

Games101笔记-模型、视图、投影

在旋转点,旋转矩阵的逆等于矩阵的转置 视图变换和投影变换 三维变换 左边3*3是线性变换,右边一列是仿射变换(平移) 先线性再平移 缩放、旋转、平移 x叉乘y得到z,y叉乘z得到x, xyz给任何两个可以得到另一个 (循环对称) z叉乘x得…

EDI在汽车主机厂配送流程中的应用

汽车主机厂的汽车配送流程始于汽车 “生产结束 ” ,止于 “交付给经销商 ” 。在这个流程中,企业作为主机厂的下游供应商,与主机厂的物流服务供应商之间的信息交换将会变得十分重要。 配送流程:运输订单以及报告 汽车主机厂提供预…

6-高维空间:机器如何面对越来越复杂的问题

声明 本文章基于哔哩哔哩付费课程《小白也能听懂的人工智能原理》。仅供学习记录、分享,严禁他用!!如有侵权,请联系删除 目录 一、知识引入 (一)二维输入数据 (二)数据特征维度 …

Java-JVM 虚拟机原理调优实战

一、基础 栈帧(Stack Frame)栈空间的 基本元素,用于 方法的调用和方法的执行的数据结构 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后&#xff0c…

小白向-使用git实现不同服务器改动的同步

背景 深度学习项目,已有可运行的backbone,已将此项目在github建库。 需要使用不同分支进行不同改动的测试;有两台服务器可供程序运行; 项目需求 以github云端仓库为媒介,实现不同服务器改动无痛关联。维护项目代码…

MS14_064 漏洞利用与安全加固

文章目录 环境说明1 MS14_064 简介2 MS14_064 复现过程3 MS14_064 安全加固 环境说明 渗透机操作系统:kali-linux-2024.1-installer-amd64漏洞复现操作系统: sc_winxp_pro_with_sp2 1 MS14_064 简介 要利用此漏洞则需要进行用户交互。通过发送电子邮件信息给本地登…

【云开发笔记No.4】DevOps的起源,定义和基本原则

DevOps,作为一组过程、方法与系统的统称,它的出现并不是偶然的,而是源于软件开发与运维领域长期以来所面临的挑战和痛点。其诞生背景可以追溯到敏捷开发模式的兴起以及持续开发所带来的运维问题。随着软件行业的飞速发展,传统的软…

Godot 学习笔记(3):IOC容器注入,以NlogServices为例

文章目录 前言环境注意事项Ioc注入文件夹设置Service服务搭建Nlog.configNlogService配置ButtonTest1Service控制反转Program主入口ButtonTest1从Ioc中获取服务 输出生命周期问题 总结 前言 Godot.Net中使用IOC之后,Godot的代码将会被极大的解耦。这里不不展开说明…

【大模型】直接在VS Code(Visual Studio Code)上安装CodeGeeX插件的过程

文章目录 一、什么是CodeGeeX(一)我理解的CodeGeeX(二)优缺点 二、CodeGeex下载、安装、注册(一)安装VS Code(Visual Studio Code)(二)下载安装CodeGeeX(三)注…

SpringBoot中使用验证码easy-captcha

easy-captcha使用的大概逻辑: 当一个请求发送到后端服务器请求验证,服务器使用easy-captcha生成一个验证码图片,并通过session将验证信息保存在服务器,当用户登录校验时候,会从ession中取出对比是否一致 但是前后端分离之后 由于跨域问题 以上就无法实现了 下面这种情况没…

Trait与生命周期

原文链接:(*∇`*) 咦,又好了~ Rust – xiaocr_bloghttp://www.xiaocr.fun/index.php/2024/03/18/trait%E4%B8%8E%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/ 目录 Trait 定义trait 默认实现 trait作为参数 Trait Bound语法 通过指定多个 trait bound …

B003-springcloud alibaba 服务治理 nacos discovery ribbon feign

目录 服务治理服务治理介绍什么是服务治理相关方案 nacos实战入门搭建nacos环境安装nacos启动nacos访问nacos 将商品微服务注册进nacos将订单微服务注册进nacos订单服务通过nacos调用商品服务 实现服务调用的负载均衡什么是负载均衡代码实现负载均衡增加一个服务提供者自定义实…

【CKA模拟题】掌握Pod日志输出的秘密

题干 For this question, please set this context (In exam, diff cluster name) 对于这个问题,请设置这个上下文(在考试中,diff cluster name) kubectl config use-context kubernetes-adminkubernetes product pod is running. when you access log…

flask之ssti [WesternCTF2018]shrine1

打开题目 整理一下,代码: import flask import osapp flask.Flask(__name__) app.config[FLAG] os.environ.pop(FLAG) app.route(/)def index():return open(__file__).read()app.route(/shrine/)def shrine(shrine):def safe_jinja(s):s s.replace((, ).replac…

无人机三维建模过程中注意事项

无人机三维建模是指利用无人机技术进行三维建模,该方法通过无人机搭载的多种传感器,如摄像头、激光扫描仪等,获取建筑物的多角度影像数据,然后利用计算机视觉技术和三维重建算法,将这些影像数据转化为高精度的三维模型…

微服务技术栈SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式(五):分布式搜索 ES-下

文章目录 一、数据聚合1.1 聚合种类1.2 DSL实现聚合1.3 RestAPI实现聚合1.4 演示:多条件聚合 二、自动补全2.1 拼音分词器2.2 自定义分词器2.3 DSL自动补全查询2.5 实现酒店搜索框自动补全2.5.1 修改酒店索引库数据结构2.5.2 RestAPI实现自动补全查询2.5.3 实战 三、…

Docker部署Django项目——基础

1.服务器配置 1.1centos7 系统的安装 centos-7-isos-x86_64安装包下载) VMware安装自定义配置 选择对应的系统镜像 一般选择内核4核、内存8g、硬盘80g 相关配置 1.2.网络配置 1.2.1查看win电脑虚拟机VMnet8的ip 使用ipconfig查看虚拟机的ip 1.2.2配置虚拟机VMnet8的ip…

196基于matlab的计算器GUI可视化

基于matlab的计算器GUI可视化,具有加减乘除功能。可作为练习使用。程序已调通,可直接运行。 196 matlab GUI可视化 计算器 - 小红书 (xiaohongshu.com)

Flutter-数字切换动画

效果 需求 数字切换时新数字从上往下进入,上个数字从上往下出新数字进入时下落到位置并带有回弹效果上个数字及新输入切换时带有透明度和缩放动画 实现 主要采用AnimatedSwitcher实现需求,代码比较简单,直接撸 import dart:math;import p…

html-docx-js-typescript——将html生成docx文档

html-docx-js-typescript源码:GitHub - caiyexiang/html-docx-js-typescript: Convert HTML documents to docx format. html-docx-js地址:html-docx-js - npm *简单使用: 获取需要转为word文档的html节点,借助file-saver提供的…