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

自学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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux安装WordPress问题汇总,老是提示无法连接到FTP服务器解决方案

最近在做一些建站相关的事情,遇到一些大大小小的问题都整理在这里 1.数据库密码和端口,千万要复杂一点,不要使用默认的3306端口 2.wordpress算是一个php应用吧,所以安装流程一般是 apache http/nginx——php——mysql——ftp &…

嵌入式学习第二十九天!(数据结构的概念、单向链表)

数据结构: 1. 定义: 一组用来保存一种或者多种特定关系的数据的集合(组织和存储数据) 1. 程序设计: 将现实中大量而复杂的问题以特定的数据类型和特定的数据结构存储在内存中,并在此基础上实现某个特定的功…

Python深度学习技术教程

原文链接:Python深度学习技术教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247597949&idx4&sn65c0d353d02b060fec98ec799f217ae1&chksmfa823e9acdf5b78cd71cfcb060e3b60125b17afbe3e19ef423d4709d2df7fc93d90ce3097253&token14787…

【K8S】docker和K8S(kubernetes)理解?docker是什么?K8S架构、Master节点 Node节点 K8S架构图

docker和K8S理解 一、docker的问世虚拟机是什么?Docker的问世?docker优点及理解 二、Kubernetes-K8SK8S是什么?简单了解K8S架构Master节点Node节点K8S架构图 一、docker的问世 在LXC(Linux container)Linux容器虚拟技术出现之前,业…

汽车功能安全整体方法

摘 要 ISO26262道路车辆功能安全标准已经制定实践了多年,主要目标是应对车辆的电子和电气(E/E)系统失效。该方法践行至今,有些系统功能安全方法已经成熟,例如电池管理系统(BMS),并且…

Javaweb学习记录(三)请求响应案例

下面为一个请求响应案例,postman发送请求,服务器响应将一个xml文件中的数据通过读取解析,将其用Result类标准的格式返回前端,在前端用json的方式显示 后端Controller代码 1、通过本类的字节码文件得到类加载器并寻找到需要解析的…

vue2使用webSocket双向通讯

基于webSocket实现双向通信,使用webworker保持心跳。 由于浏览器的资源管理策略会暂停或限制某些资源的消耗,导致前端心跳包任务时效,后端接收不到webSocket心跳主动断开,因此需要使用webworker保持心跳 引入webworker npm insta…

【Ubuntu】Ubuntu的安装和配置

下载ubuntu镜像 https://releases.ubuntu.com/22.04.4/ubuntu-22.04.4-desktop-amd64.iso 一、Ubuntu安装 1.新建虚拟机 1.1按照它的提示创建用户;后面一直下一步就好 2.启动Ubuntu虚拟机 2.1设置为中文键盘 2.2默认即可;若是有低需求也可以选择最小…

Coursera上Golang专项课程3:Concurrency in Go 学习笔记(完结)

Concurrency in Go 本文是 Concurrency in Go 这门课的学习笔记,如有侵权,请联系删除。 文章目录 Concurrency in GoMODULE 1: Why Use Concurrency?Learning Objectives M1.1.1 - Parallel ExecutionM1.1.2 - Von Neumann BottleneckM1.1.3 - Power W…

Python基础(六)之数值类型元组

Python基础(六)之数值类型元组 1、简介 元组: 在Python中是内置的数据结构之一,是一个不可变的序列,切可以是任何类型数据。元组的元素放在()小括号内。一般我们希望数据不改变的时候使用 不可变与可变的…

Day69:WEB攻防-Java安全JWT攻防Swagger自动化算法签名密匙Druid泄漏

目录 Java安全-Druid监控-未授权访问&信息泄漏 黑盒发现 白盒发现 攻击点 Java安全-Swagger接口-导入&联动批量测试 黑盒发现 白盒发现 自动化发包测试 自动化漏洞测试 Java安全-JWT令牌-空算法&未签名&密匙提取 识别 JWT 方式一:人工识…

web渗透测试漏洞复现:Elasticsearch未授权漏洞复现

web渗透测试漏洞复现 Elasticsearch未授权漏洞复现Elasticsearch简介Elasticsearch复现Elasticsearch漏洞修复和加固措施 Elasticsearch未授权漏洞复现 Elasticsearch简介 Elasticsearch 是一款 Java 编写的企业级搜索服务,它以分布式多用户能力和全文搜索引擎为特…

使用jenkins-pipeline进行利用项目文件自动化部署到k8s上

Discard old builds:丢弃旧的构建,目的是管理存储空间、提升性能以及保持环境整洁 Do not allow concurrent builds: 禁止并发构建是指同一时间内只允许一个构建任务执行,避免多个构建同时运行可能带来的问题 Do not allow the pipeline to resume if the controller resta…

RPC学习笔记一

什么是RPC RPC(Remote Procedure Call,远程过程调用)是一种用于实现分布式系统中不同计算机或进程之间进行通信和调用的技术和模式。 在传统的过程调用中,当一个程序需要调用另一个程序的函数或方法时,通常是在同一台…

ChatGPT4的Dalle-3 生成电影海报及升级教程

引言 首先DALL E3首先需要升级为ChatGPT4才能使用,接下来从以下几个方面进行介绍: 一、ChatGPT4中的DALL E3 的电影海报二、ChatGPT4下的DALL E3的实例三、ChatGPT4的升级教程 一、ChatGPT4中的DALL E3 的电影海报 DALLE 3可以直接在画面中识别和生成…

【Qt图形界面引擎(一)】:第一个Qt程序

跨平台图形界面引擎,接口简单,易上手,一定程度简化内存。 Qt发展史 1991年由Qt Company开发的跨平台C图形用户界面应用程序开发框架2008年,Qt Company科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具2012…

【vue elementUI】修改el-dropdown样式

实现效果如下&#xff1a; 代码如下&#xff1a; <el-dropdown trigger"click" command"handleCommand" active-text-color"#606266"><span class"product-card">{{getCategoryName(categoryId)}}</span><el-dro…

一文解决内网传外网sftp没跑满带宽问题

随着企业网络的日益复杂&#xff0c;内部网络与外部网络之间的文件传输需求不断增长。然而&#xff0c;标准的SFTP协议在跨网络传输时常常无法充分运用可用带宽&#xff0c;导致传输效率不尽人意。本文旨在探讨影响内网至外网SFTP传输效率的因素&#xff0c;并结合一种高效的解…

Uibot (RPA设计软件)财务会计Web应用自动化(批量开票机器人)

Uibot (RPA设计软件&#xff09;Mage AI智能识别&#xff08;发票识别&#xff09;———机器人的小项目友友们可以参考小北的课前材料五博客~ (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff09; 紧接着小北的前两篇博客&#xff0c;友友们我们…

Vue+SpringBoot打造数据可视化的智慧河南大屏

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 数据模块 A4.2 数据模块 B4.3 数据模块 C4.4 数据模块 D4.5 数据模块 E 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数据可视化的智慧河南大屏&#xff0c;包含了GDP、…