跳转至

API

netspy.AirSpider

Bases: BaseParser

start()

启动爬虫,阻塞至结束。

stop()

请求提前停止(优雅排空)。

netspy.Spider

Bases: BaseParser

start()

启动爬虫。keep_alive=False 时爬完退出;否则常驻轮询队列。

stop()

netspy.TaskSpider

Bases: Spider

task_requests(task)

把一个任务(dict)变成一个或多个 Request。必须实现。

fetch_tasks(limit)

拉一批任务。默认从 Redis list 取;覆写以从 MySQL / Mongo 查。

add_tasks(*tasks)

运行中追加任务(比如在 parse 里发现了新的待抓项)。

push_tasks(*tasks, task_key=None) classmethod

生产者用:把任务塞进 Redis 任务源。

task_key 默认是类名,不是消费者那边的 redis_key——这里是 classmethod,拿不到任何实例的 redis_key。消费者如果自定义了 redis_key 却没给它显式传 task_key,它的任务源默认会跟着 redis_key 走;这时必须在这里也显式传同一个 task_key (通常就传那个 redis_key 的值),否则推的任务和消费者读的是两个 不同的 Redis key——推了但没人读,消费者看到空队列直接判定「任务耗尽」 退出,不会有任何报错。

start()

stop()

netspy.BatchSpider

Bases: BaseParser

task_requests(task)

把一个任务(任务表的一行 dict)变成一个或多个 Request。必须实现。

框架会自动给每个 Request 补上 cb_kwargs['task'],回调里可直接拿到。

update_task(task_id, *, ok=True)

回写任务状态:ok=True → 已完成;ok=False → 失败(不再重试)。

标「已完成」会等这次请求产出的数据真正落库之后才写任务表。 照文档在回调里 yield 完 item 紧接着调用它 —— 那一刻数据还只在内存缓冲里, 立刻写 DONE 的话,节点一死数据就没了,而防丢机制只回收「处理中」, 标了 DONE 的任务永远不会被重跑。真库实测:5 个任务全标 DONE,落库 0 行。

三条例外走立即写入:没产出 item 的请求(否则永远等不到落库)、 ok=False(标失败不取决于数据)、以及不在请求上下文里调用(比如 master)。

failed_request(request, response)

重试耗尽后:把对应任务标为失败。覆写时记得 super()。

start()

worker:消费 master 推来的任务。

start_monitor(*, once=False)

master:管理批次生命周期。once=True 跑完一个批次即返回。

stop()

netspy.core.batch_store.BatchStore

Bases: ABC

ensure_schema() abstractmethod

建批次记录表(幂等)。任务表由用户自行创建。

latest_batch() abstractmethod

最近一个批次(不管是否完成),没有则 None。

batch_age_seconds(batch_id) abstractmethod

批次创建至今的秒数。

reset_all_tasks() abstractmethod

所有任务状态 → 待处理(开新批次时调用)。

reset_lost_tasks(stale_seconds) abstractmethod

「处理中」且超过 stale_seconds 没更新的任务 → 待处理;返回重置数量。

claim_tasks(limit) abstractmethod

认领至多 limit 个待处理任务(状态置为处理中),返回整行。

mark_task(task_id, state) abstractmethod

回写单个任务状态(worker 解析完成 / 失败后调用)。

close()

释放连接。

netspy.core.batch_monitor.BatchMonitor

run()

常驻:批次之间按 batch_interval 间隔调度。

run_once()

把当前批次跑到完成并返回。未到下一批时间也会强制开一个新批次。

stop()

netspy.BaseParser

Bases: LoggerMixin

start_requests()

产出种子请求。

parse(request, response)

默认回调。未给 Request 指定 callback 时调用。

download_midware(request)

下载前的最后一次修改机会。返回 Request 以替换,返回 None 用原请求。

validate(request, response)

校验响应。返回 False 丢弃;抛 ValidationError 触发重试;抛 NotRetryError 丢弃。

failed_request(request, response)

重试耗尽后的兜底。可再 yield Request / 数据。

exception_request(request, response, exception)

下载 / 解析抛异常且仍会重试时调用(观测用,通常不 yield)。

user_pool()

返回一个账号池,返回 None 表示不用。调度器会自动挂到下载链上。

check_login(response)

用了账号池时判断响应是否处于登录态。返回 False -> 拉黑当前账号并换号重试。

start_callback()

爬虫启动时调用一次。

end_callback()

爬虫正常结束时调用一次。

netspy.Request

download(downloader=None)

立即下载并返回 :class:Response(阶段 02 前用于独立调试)。

netspy.Response

from_httpx(resp, request=None, content=None) classmethod

content 由流式下载的调用方传入 —— 流式响应上取 resp.content 会抛 ResponseNotRead,而且那样也绕开了大小上限。

from_curl_cffi(resp, request=None, content=None) classmethod

由 :mod:curl_cffi 的响应构造(与 :meth:from_httpx 平行)。

与 httpx 的差异:elapsed 已经是秒(float)而非 timedelta, 编码属性叫 charset_encodinghistory 里是完整响应对象。

netspy.Item

pre_to_db()

保存前钩子。子类覆写做字段清洗 / 补全。

netspy.UpdateItem

Bases: Item

netspy.pipelines.base.BasePipeline

Bases: LoggerMixin, ABC

save_items(table, items) abstractmethod

批量写入。返回 False 时该批会被 dump 到 failed_items,且不写去重指纹。

update_items(table, items, update_keys)

update_keys upsert。仅当爬虫用 UpdateItem 时才需要实现。

close()

爬虫结束时调用,释放连接 / 文件句柄。

netspy.pipelines.mysql.MysqlPipeline

Bases: SqlPipeline

netspy.db.mysqldb.MysqlDB

from_url(url) classmethod

mysql://user:pass@host:3306/dbname

transaction()

同一条连接上跑多条语句,出错回滚。

普通的 query / execute 各自从池里借一条连接、用完就还,而且池是 autocommit=True 的 —— 所以「先 SELECT ... FOR UPDATE 再 UPDATE」 这种写法在它们身上根本锁不住:两条语句在两条连接、两个事务里, 行锁在第一条语句结束时就放掉了。

需要「读到什么就锁住什么」的地方(比如多 worker 抢任务)必须用这个。

insert(sql, args=None)

执行一条 INSERT,返回自增主键(cursor.lastrowid)。

netspy.User dataclass

netspy.network.user_pool.base.UserPool

Bases: LoggerMixin, ABC

get() abstractmethod

借一个可用账号;没有可用的返回 None。

report_ok(user)

账号用完且正常,归还池子。

report_bad(user, *, block_seconds=1800.0)

账号被封 / cookie 失效,拉黑 block_seconds 秒。

close()

释放资源。

netspy.LocalUserPool

Bases: UserPool

netspy.GuestUserPool

Bases: LocalUserPool

netspy.RedisUserPool

Bases: UserPool

netspy.network.middleware.DownloaderMiddleware

Bases: LoggerMixin

基类,子类按需覆写。子类里可以直接 self.logger.info(...)

netspy.network.proxy_pool.base.ProxyPool

Bases: ABC

get_proxy() abstractmethod

返回一个可用代理(形如 http://host:port),无则返回 None。

report_bad(proxy)

标记某代理不可用 —— 确定是代理自己的错(连不上、CONNECT 被拒)。

report_suspect(proxy)

一次说不清是谁的错的失败(读超时、连接重置、响应畸形)。

默认不作为 —— 自定义代理池不实现它,就等于「目标站的锅不算代理头上」, 这是安全的方向。内置的 ApiProxyPool 会连续攒够 PROXY_SUSPECT_BAN_AFTER 次才拉黑。

report_good(proxy)

这个代理刚成功完成了一次请求 —— 用来把连续失败计数清零。

⚠️ 它在每个成功请求上都会被调用,实现必须便宜。

close()

释放资源。