Coder Social home page Coder Social logo

spiderman's Introduction

spiderman

基于 scrapy-redis 的通用分布式爬虫框架


目录

demo采集效果

image

image

image

爬虫元数据

meta

cluster模式

cluster

standalone模式

image-20210323141940525

附件下载

image-20210318161618307

kafka实时采集监控

mon

功能

  • 自动建表

  • 自动生成爬虫代码,只需编写少量代码即可完成分布式爬虫

  • 自动存储元数据,分析统计和补爬都很方便

  • 适合多站点开发,每个爬虫独立定制,互不影响

  • 调用方便,可以根据传参自定义采集的页数以及启用的爬虫数量

  • 扩展简易,可以根据需要选择采集模式,单机 standalone (默认) 或者 分布式cluster

  • 采集数据落地方便,支持多种数据库,只需在 spider 中启用相关的管道

    关系型

    • mysql
    • sqlserver
    • oracle
    • postgresql
    • sqlite3

    非关系型

    • hbase
    • mongodb
    • elasticsearch
    • hdfs
    • hive
    • doris
    • datafile, 比如 csv
  • 反爬处理简易,已封装各种反爬中间件

    • 随机 UserAgent
    • 定制请求头 Headers
    • 定制 Cookies 池
    • 定制代理 ip
    • 在 scrapy 中使用 requests
    • Payload 请求
    • 使用 Splash 渲染 js

原理说明

  1. 消息队列使用 redis,采集策略使用广度优先,先进先出
  2. 每个爬虫都有一个 job 文件,使用 job 来生成初始请求类 ScheduledRequest,并将其推送到 redis; 初始请求全部推到 redis 后,运行 spider 解析生成数据 并迭代新的请求到redis, 直到 redis 中的全部请求被消耗完
# scrapy_redis请求类
class ScheduledRequest:

    def __init__(self, **kwargs):
        self.url = kwargs.get('url')                 # 请求url
        self.method = kwargs.get('method', 'GET')   # 请求方式 默认get
        self.callback = kwargs.get('callback')  # 回调函数,指定spider的解析函数
        self.body = kwargs.get('body')  # body, method为post时, 作为 post表单
        self.meta = kwargs.get('meta')  # meta, 携带元数据,比如 pagenum
  1. item 类定义表名、字段名、排序号(自定义字段顺序)、注释说明(便于管理元数据)、字段类型(仅关系型数据库管道有效)
class zhifang_list_Item(scrapy.Item):
    #  define table
    tablename = 'zhifang_list'
    tabledesc = '列表'
    # define the fields for your item here like:
    # 关系型数据库,可以自定义字段的类型、长度,默认 VARCHAR(length=255)
    # colname = scrapy.Field({'idx': 1, 'comment': '名称', 'type': VARCHAR(255)})
    tit = scrapy.Field({'idx': 1, 'comment': '房屋标题'})
    txt = scrapy.Field({'idx': 2, 'comment': '房屋描述'})
    tit2 = scrapy.Field({'idx': 3, 'comment': '房屋楼层'})
    price = scrapy.Field({'idx': 4, 'comment': '房屋价格'})
    agent = scrapy.Field({'idx': 5, 'comment': '房屋中介'})
    # default column
    detail_full_url = scrapy.Field({'idx': 100, 'comment': '详情链接'})  # 通用字段
    pkey = scrapy.Field({'idx': 101, 'comment': 'md5(detail_full_url)'})  # 通用字段
    pagenum = scrapy.Field({'idx': 102, 'comment': '页码'})  # 通用字段
  1. 去重策略,默认不去重,每次采集独立,即每次启动 job 都会清空上一次未完成的 url,并且不保留 redis 中上一次已采集的 url 指纹。 如需调整可以修改以下配置
  • job 文件(单个爬虫)
class zhifang_job(SPJob):

    def __init__(self):
        super().__init__(spider_name=zhifang_Spider.name)
        # self.delete()   # 如需去重、增量采集,请注释该行
  • spider 文件(单个爬虫)
    custom_settings = {
        ...,
        'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter',
        'SCHEDULER_PERSIST': True, # 开启持久化
    }
   
    def get_callback(self, callback):
        # url去重设置:True 不去重 False 去重
        callback_dt = {
            'list': (self.list_parse, False),
            'detail': (self.detail_parse, False),
        }
        return callback_dt.get(callback)
  • 布隆过滤器。

当采集的数据量很大时,可以使用布隆过滤器,该算法占用空间小且可控,适合海量数据去重。 但是该算法会有漏失率,对爬虫而言就是漏爬。可以通过调整过滤器负载个数、内存配置、哈希次数以降低漏失率。 默认 1 个过滤器,256 M 内存,使用 7 个 seeds,这个配置表示漏失概率为 8.56e-05 时,可满足 0.93 亿条字符串的去重。当漏失率为 0.000112 时,可满足 0.98 亿条字符串的去重。调参与漏失率参考

    custom_settings = {
        ...,
        'DUPEFILTER_CLASS': 'SP.bloom_dupefilter.BloomRFDupeFilter',  # 使用布隆过滤器
        'SCHEDULER_PERSIST': True,  # 开启持久化
        'BLOOM_NUM': 1,  # 布隆过滤器负载个数,当内存达到限制时,可以增加负载个数
        'BLOOM_MEM': 256,  # 布隆过滤器内存大小(单位 M),内存最大 512 M (因为 redis string 最大只能 512 M)
        'BLOOM_K': 7,  # 布隆过滤器哈希次数,次数越少,去重越快,但是漏失率越高
    }
   
    def get_callback(self, callback):
        # url去重设置:True 不去重 False 去重
        callback_dt = {
            'list': (self.list_parse, False),
            'detail': (self.detail_parse, False),
        }
        return callback_dt.get(callback)

下载安装

  1. git clone https://github.com/TurboWay/spiderman.git; cd spiderman;
  2. 【不使用虚拟环境的话,可以跳过步骤23】virtualenv -p /usr/bin/python3 venv
  3. 【不使用虚拟环境的话,可以跳过步骤23】source venv/bin/activate
  4. pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
  5. 修改配置 vi SP/settings.py
  6. 运行demo示例 python SP_JOBS/zhifang_job.py

如何开发一个新爬虫

运行 easy_scrapy.py 会根据模板自动生成以下代码文件,并自动在编辑器打开 spidername_job.py 文件;

类别 路径 说明
job SP_JOBS/spidername_job.py 编写初始请求
spider SP/spiders/spidername.py 编写解析规则,产生新的请求
items SP/items/spidername_items.py 定义表名字段

以上代码文件编写完成后,直接执行 python SP_JOBS/spidername_job.py

或者动态传参(参数说明 -p 采集页数, -n 启用爬虫数量) python SP_JOBS/spidername_job.py -p 10 -n 1

如何进行补爬

运行 easy_scrapy.py 会根据模板自动生成以下代码文件,并自动在编辑器打开 spidername_job_patch.py 文件;

类别 路径 说明
job SP_JOBS/spidername_job_patch.py 编写补爬请求

以上代码文件编写完成后,直接执行 python SP_JOBS/spidername_job_patch.py

如何下载附件

提供两种方式下载:

  • 1、直接在 spider 中启用附件下载管道
  • 2、使用自定义的下载器 execute_download.py 传参下载

jpg/pdf/word...等各种各样的文件,统称为附件。 下载附件是比较占用带宽的行为,所以在大规模采集中,最好是先把结构化的表数据、附件的元数据入库, 保证数据的完整性,然后再根据需要,通过下载器进行附件下载。

如何扩展分布式爬虫

采集模式有两种(在 settings 控制): 单机 standalone(默认) 和 集群分布式

如果想切换成分布式爬虫,需要在 spiderman/SP/settings.py 中启用以下配置

注意:前提是 所有SLAVE机器的爬虫代码一致、python环境一致,都可以运行爬虫demo

# 集群模式 False 单机 (默认);  True 分布式 需要配置下方的 slaves
CLUSTER_ENABLE = True
配置名称 意义 示例
SLAVES 【二选一】爬虫机器配置列表 [{'host': '172.16.122.12', 'port': 22, 'user': 'spider', 'pwd': 'spider'},
{'host': '172.16.122.13', 'port': 22, 'user': 'spider', 'pwd': 'spider'} ]
SLAVES_BALANCE 【二选一】爬虫机器配置(ssh负载均衡) {'host': '172.16.122.11', 'port': 2202, 'user': 'spider', 'pwd': 'spider'}
SLAVES_ENV 【可选】爬虫机器虚拟环境路径 /home/spider/workspace/spiderman/venv
SLAVES_WORKSPACE 【必填】爬虫机器代码工程路径 /home/spider/workspace/spiderman

如何管理爬虫元数据

运行 easy_meta.py 自动生成当前项目所有爬虫的元数据, 默认记录到sqlite meta.db, 可以在 setting 中自行配置;

# 爬虫 meta
META_ENGINE = 'sqlite:///meta.db'

元数据表meta字典如下:

字段名 类型 注释
spider varchar(50) 爬虫名
spider_comment varchar(100) 爬虫描述
tb varchar(50) 表名
tb_comment varchar(100) 表描述
col_px int 字段序号
col varchar(50) 字段名
col_comment varchar(100) 字段描述
author varchar(20) 开发人员
addtime varchar(20) 开发时间
insertime varchar(20) 元数据更新时间

如何配合kafka做实时采集监控

  1. 配置 kafka(修改 setting 的 KAFKA_SERVERS)
  2. 自定义监控规则(修改编写 kafka_mon.py , 并运行该脚本程序, 开始监控)
  3. 在 spider 中启用 kafka 管道(运行爬虫 job , 开始采集)

如何使用爬虫api

直接运行 api.py,然后可以通过 http://127.0.0.1:2021/docs 查看相关的 api 文档

注意事项

  1. 字段名称不能使用 tablename、isload、ctime、bizdate、spider 等字段,因为这些字段被作为通用字段,避免冲突
  2. items 文件每个字段建议添加注释,生成元数据时,会将注释导入到元数据表,便于管理爬虫

hive环境问题

在 windows 环境下,使用 python3 连接 hive 会有很多坑,所以使用 hdfs 管道时,hive 自动建表功能默认关闭,便于部署。 假如需要启用 hive 自动建表功能,请进行如下操作:

  1. pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
  2. pip install --no-deps thrift-sasl==0.2.1
  3. 验证环境,执行 SP.utils.ctrl_hive

如果执行成功,说明 hive 环境准备完毕,可以直接启用 hive 自动建表功能;如果遇到问题,可以参考 【大数据】windows 下python3连接hive

更新日志

日期 更新内容
20200803 1.使用更优雅的方式来生成元数据;
2.管道函数传参的写法调整;
3.附件表通用字段更名:下载状态 (isload => status)
20200831 1.解决数据入库失败时,一直重试入库的问题;
2.所有管道优化,入库失败时,自动切换成逐行入库,只丢弃异常记录
20201104 1.requests 中间件支持 DOWNLOAD_TIMEOUT、DOWNLOAD_DELAY
20201212 1.payload 中间件支持 DOWNLOAD_TIMEOUT、DOWNLOAD_DELAY;
2.get_sp_cookies 方法优化,使用轻量级的 splash 替换 selenium;
3.md 的原理部分增加去重策略的说明
20210105 1.增加布隆过滤器
20210217 1.elasticsearch 管道调整,兼容 elasticsearch7 以上版本,直接使用表名作为索引名
20210314 1.所有反爬中间件合并到 SPMiddleWare
20210315 1.使用更优雅的方式生成 job 初始请求;
2.headers 中间件优化,减少 redis 的内存占用;
3.删除 cookie 中间件,cookie 只是 headers 里面的一个值,可以直接使用 headers 中间件;
4.删除 Payload 中间件,Payload 请求可以直接使用 requests 中间件
5.增加 CookiesPool 中间件,用于需要多个账号随机切换采集的场景
20210317 1.增加可以脱离 scrapy 独立工作的、支持分布式的附件下载器
20210318 1.增加 api 服务
20210323 1.job 日志输出优化
20210330 1.kafka 管道优化,如果主题有多个分区,则数据均匀地写到每个分区
20230210 1.增加支持 Apache Doris

spiderman's People

Contributors

dependabot[bot] avatar turboway avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spiderman's Issues

关于代理中间件

开启了代理中间件后 在文件中输入了帐号密码 然后访问全部407了
image

demo 运行没爬到东西

image

查过日志和代码
启动可以正常加入 redis start url

但是启动爬虫后 貌似没有执行 make_request_from_data 这个函数不会进 麻烦大佬拯救一下
于是乎 什么都没有爬到

另外 无论用不用虚拟环境 requirements.txt 安装环境都会报错

python 3.10
linux manjaro
执行命令 python SP_JOBS/zhifang_job.py

如何在一个进程中启动多个爬虫

当前的做法是 python SP_JOBS/zhifang_job.py 这样只能启动一类爬虫
如果想启动多个的话 就要执行多个进程
问题如下:

  1. 可否在一个进程中执行
  2. 多爬虫启动 两种方案哪种更好 (效率方面)

关于框架的两个警告

1 启动时
[py.warnings] WARNING: /home/donney/.local/lib/python3.10/site-packages/scrapy/utils/request.py:232: ScrapyDeprecationWarning: '2.6' is a deprecated value for the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting.

It is also the default value. In other words, it is normal to get this warning if you have not defined a value for the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting. This is so for backward compatibility reasons, but it will change in a future version of Scrapy.

See the documentation of the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting for information on how to handle this deprecation.
return cls(crawler)

2.运行中
2023-02-17 15:30:32 [py.warnings] WARNING: /home/donney/.local/lib/python3.10/site-packages/scrapy_redis/spiders.py:197: ScrapyDeprecationWarning: Passing a 'spider' argument to ExecutionEngine.crawl is deprecated
self.crawler.engine.crawl(req, spider=self)

麻烦大佬看一下 尝试修没有好

开启了布隆过滤器 数据库中有重复内容

开启了布隆过滤器
image
单个爬虫并发数 5
地址已经设置了去重
image

然后启动job 爬虫数量5 页数5
爬取完毕后 数据库有重复内容 貌似没有过滤成功
目前在单台物理机上 只有启动一个爬虫是正常

添加相同网址的任务,第二次添加的任务没有执行

EXTENSIONS设置为空,通过ScheduledRequest添加任务,两次任务的网址如果一样,第二次添加的网址不工作。

跟踪到第二次添加任务后,执行到scrapy engine.py schedule函数,执行了self.signals.send_catch_log。
然后后面就不知道代码运行到哪里去了。

推测某个步骤有过滤功能,把第二次添加的任务过滤掉了。

请问过滤的步骤在哪个文件哪个函数?

蜘蛛配置如下:
'EXTENSIONS': {},

    def get_callback(self, callback):
        # url去重设置:True 不去重 False 去重
        callback_dt = {
            'list': (self.list_parse, True),
            'detail': (self.detail_parse, True),
        }
        return callback_dt.get(callback)

转化scrapy请求失败问题

运行时make_request_from_data并没有被调用,scrapy没有被启动是怎么回事,但redis中是有内容的。

爬虫命令到request之间的时间如何缩短?

我在spiderman外层套了一个对外的api接口,接收到请求后,执行采集,然后返回采集结果。
测试过程中发现从接到请求到返回结果之间的时间过长。预期时长500毫秒内。目前测试发现可能延长到了5秒左右,不知道是什么原因造成的。

爬虫命令的位置:
[SP_JOBS>>job.py>>SPJob>>run]
p = subprocess.Popen(cmd, shell=True)

Request的位置:
[SP>>spiders>>SPRedisSpider.py>>SPRedisSpider>>make_request_from_data]
return Request(**params)

执行采集过程中发现从启动爬虫命令到request之间的时间花费大约2-4秒。请问这个时间是否可压缩?

关于Splash使用的问题

起因: 之前steam爬虫 会被年龄验证页面卡住
过程: 查询大量资料后 发现用splash渲染低频页面 并且跑一个lua脚本可以解决
image

但是我把代码尝试移动到框架中时却发现无效且有警告
2023-02-17 17:27:27 [py.warnings] WARNING: /home/donney/.local/lib/python3.10/site-packages/scrapy_redis/dupefilter.py:115: ScrapyDeprecationWarning: Call to deprecated function scrapy.utils.request.request_fingerprint().

If you are using this function in a Scrapy component, and you are OK with users of your component changing the fingerprinting algorithm through settings, use crawler.request_fingerprinter.fingerprint() instead in your Scrapy component (you can get the crawler object from the 'from_crawler' class method).

Otherwise, consider using the scrapy.utils.request.fingerprint() function instead.

Either way, the resulting fingerprints will be returned as bytes, not as a string, and they will also be different from those generated by 'request_fingerprint()'. Before you switch, make sure that you understand the consequences of this (e.g. cache invalidation) and are OK with them; otherwise, consider implementing your own function which returns the same fingerprints as the deprecated 'request_fingerprint()' function.
return request_fingerprint(request)

未找到numpy对应版本

按照说明安装依赖,找不到numpy对应版本

Could not find a version that satisfies the requirement numpy==1.18.4

运行一段时间后报错

爬虫运行一段时间后报错如下,然后就中断无法运行了
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/scrapy/core/downloader/middleware.py", line 44, in process_request
return (yield download_func(request=request, spider=spider))
twisted.web._newclient.ResponseNeverReceived: [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]

关于cookies使用的问题

问题: 在学习爬取steam的过程中 遇到了年龄验证的问题 查询解决方案是使用 cookies
发现在框架中 配置了好像没什么效果 是我的格式有问题吗?
image

分布式模式下INFO信息有误

我配置了一台Slave,爬取结果是成功的,但是在Pycharm的console里输出一直是slave:localhost.localdomain爬虫执行成功,调试的时候连接的SSH的hostname确实是我配置的slave 的host,但是msg_out却是localhost,为什么呢

关于demo采集

2023-05-07 23:35:36 [spiderman.model.standalone] ERROR: 爬虫执行失败:2023-05-07 23:35:36 [scrapy.utils.log] INFO: Scrapy 2.6.2 started (bot: SP)
2023-05-07 23:35:36 [scrapy.utils.log] INFO: Versions: lxml 4.9.1.0, libxml2 2.9.12, cssselect 1.1.0, parsel 1.6.0, w3lib 1.21.0, Twisted 22.10.0, Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)], pyOpenSSL 23.1.1 (OpenSSL 3.0.8 7 Feb 2023), cryptography 39.0.1, Platform Windows-10-10.0.19041-SP0
2023-05-07 23:35:36 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'SP',
'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter',
'LOG_FILE': 'D:/GitHub/spiderman/SP_log/20230507/zhifang.log',
'LOG_LEVEL': 'INFO',
'NEWSPIDER_MODULE': 'SP.spiders',
'RETRY_HTTP_CODES': [500, 502, 503, 504, 522, 524, 408, 400, 403, 404],
'RETRY_TIMES': 3,
'SCHEDULER': 'scrapy_redis.scheduler.Scheduler',
'SPIDER_MODULES': ['SP.spiders'],
'USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, '
'like Gecko) Chrome/62.0.3202.75 Safari/537.36'}
Unhandled error in Deferred:

作者您好!请问运行demo的时候出现这种错误该如何解决?

如何先启动所有爬虫,然后再向单个爬虫投递网址

目前的任务逻辑是,先make_job, 然后生成爬虫启动命令scrapy crawl xxx,启动爬虫并开始采集。

这就造成每次执行采集,就要先等待爬虫启动。

这样的启动过程需要耗时5秒左右,无法适应即时采集的需求。

我在spiderman的外层套了一层sanic的restful api,接收到API请求后,执行job=xxx_job, job.make_job, job.crawl。这个过程就是启动爬虫和开始采集的过程。这个启动很要命,时间太长了。

我这几天研究了好几天,无奈才疏学浅,没有实现先启动后接收采集任务。

请问可否提供一个改造的思路,所有爬虫一次性启动,等待接收采集任务。接到任务后,立即开始采集并返回结果。

谢谢!

kafka监控程序运行报错

Traceback (most recent call last):
File "C:\Users\chengzhang\AppData\Local\Programs\Python\Python39\lib\site-packages\kafka\consumer\fetcher.py", line 445, in _message_generator
raise StopIteration('Subscription needs partition assignment')
StopIteration: Subscription needs partition assignment

是consumer.subscribe()需要别的参数吗,我看运行实例图片上也只有topics=['zhifang',]这一个参数

cookies 定制格式 和 cookie池 怎么设置

def __init__(self):
    super().__init__(spider_name=zhifang_Spider.name)
    self.delete()  # 如需去重、增量采集,请注释该行
    self.headers = {
        # 有反爬的话,可以在这边定制请求头
    }
    self.cookies = (
        # 多账号采集的话,可以在这边定制多个 cookie string
       
    )

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.