Skip to content

Commit

Permalink
📃 docs(readme): customization docs
Browse files Browse the repository at this point in the history
  • Loading branch information
iiicebearrr committed Jan 13, 2024
1 parent fb18b6f commit 951ebc0
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 8 deletions.
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [Installation](#installation)
- [Documentation](#documentation)
- [Roadmap](#roadmap)
- [Customization](#customization)
- [Known Issues](#known-issues)

# Quick Preview
Expand Down Expand Up @@ -61,6 +62,71 @@ pip install spiders-for-all # python 版本 >= 3.12
- [ ] 爬取笔记评论
- [ ] GUI

# Customization

**如果你想自定义爬虫, 可以参考以下指引**

首先需要了解一下项目爬虫的基本结构, 参考下图:

![spider_structure](docs/spider.png)

- `spiders_for_all/spiders`目录下存放各个平台的爬虫, 每个爬虫都是一个类, 继承自`spiders_for_all.core.spider.BaseSpider`类, 并实现`BaseSpider`类的`get_items_from_response`方法
- 继承自`BaseSpider`的爬虫, 会按照以下流程爬取目标网站数据
- `self.__init__`: 初始化爬虫
- 初始化logger
- 初始化数据库连接
- 初始化数据库表, 这一步的行为取决于`cls.db_action_on_init`:
- `spiders_for_all.core.spider.DbActionOnInit.CREATE_IF_NOT_EXISTS`: 如果表不存在则创建
- `spiders_for_all.core.spider.DbActionOnInit.DROP_AND_CREATE`: 直接删除并创建表
- 初始化client:
- `client`是一个`spiders_for_all.core.client.HttpClient`对象, 封装了失败重试、日志、以及生成模拟请求头`user-agent`的功能
- `self.run`: 运行爬虫
- `self.before`: 运行爬虫前执行的代码, 默认会打印一条日志
- `self.get_items`: 从目标网站获取数据
- `self.request_items`: 向`self.api`发送请求, 获取返回。会调用`self.get_request_args`获取额外的请求参数比如`params`, `data`等等
- `self.validate_response`: 验证返回体结构, 如果定义了`self.response_model`, 会调用`self.response_model`基于`pydantic`对返回体进行验证。**注意这里的验证是业务验证, 不是HTTP状态的验证, `self.client`会自动验证HTTP状态。** 如果没有定义`self.response_model`, 则不会进行验证,直接返回原始的`requests.Response`对象
- `self.get_items_from_response`: 从验证成功的返回体中取出对应的items, 返回items的数据类型完全取决于`cls.item_model`, 具体可以参考几个爬虫的实现
- **需要注意的是, `self.request_items()`, `self.validate_response`, `self.get_items_from_response`均被封装在一个`retry`的wrapper内,这也就意味着如果出现: `HTTP状态码非200`, `业务返回体异常, 比如哔哩哔哩的-352业务码`, `获取items失败,比如网页没有返回正常的数据`这些情况, 均会触发自动重试**
- `self.save_items`: 将爬取的数据保存到数据库
- `self.after`: 运行爬虫后执行的代码, 默认会打印一条日志

- 除此之外, 需要额外定义一些类属性, 示例如下

```python
import typing as t
import logging
import requests
from sqlalchemy import orm
from pydantic import BaseModel
from spiders_for_all.core.response import Response
from spiders_for_all.core.spider import BaseSpider, DbActionOnInit, DbActionOnSave
from spiders_for_all.database.session import SessionManager
from spiders_for_all.utils.logger import default_logger

class MySpider(BaseSpider):
api: str # 目标API, 必须
name: str # 爬虫名称, 必须
alias: str # 爬虫别名, 必须
platform: str # 爬虫所属平台, 必须
description: str = "" # 爬虫描述, 可选

database_model: t.Type[orm.DeclarativeBase] # 数据库表模型, 必须
item_model: t.Type[BaseModel] # 爬取的数据模型, 必须
response_model: t.Type[Response] | None = None # 返回体模型, 可选

logger: logging.Logger = default_logger # 日志对象, 可选
session_manager: SessionManager # 数据库连接管理器, 必须

insert_batch_size: int = 100 # 批量插入数据库时的批量大小, 可选

db_action_on_init: DbActionOnInit = DbActionOnInit.CREATE_IF_NOT_EXIST # 初始化数据库表时的行为, 可选
db_action_on_save: DbActionOnSave = DbActionOnSave.DELETE_AND_CREATE # 保存数据时的行为, 可选

def get_items_from_response(self, response: requests.Response | Response) -> t.Iterable[BaseModel]:
# 从返回体中取出items, 必须
pass
```

# Known Issues

- [ ] 小红书爬取用户投稿的笔记时, 由于小红书签名算法的问题尚未解决, 只能爬取用户投稿的首页数据, 需要下拉加载的数据暂时无法爬取
Expand Down
Binary file added docs/spider.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions spiders_for_all/core/spider.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from sqlalchemy.dialects import sqlite

from spiders_for_all.conf import settings
from spiders_for_all.core.client import HttpClient
from spiders_for_all.core.client import HttpClient, RequestKwargs
from spiders_for_all.core.response import Response
from spiders_for_all.database.session import SessionManager
from spiders_for_all.utils.decorator import retry
Expand Down Expand Up @@ -159,6 +159,9 @@ def get_items_from_response(
) -> t.Iterable[BaseModel]:
raise NotImplementedError()

def request_items(self, method: str, url: str, **kwargs: t.Unpack[RequestKwargs]):
return self.client.request(method, url, **kwargs)

def _get_items(self) -> t.Iterable[BaseModel]:
# Note: get_items_from_response and validate_response should be retried either if failed
@retry(
Expand All @@ -175,7 +178,7 @@ def _get_items(self) -> t.Iterable[BaseModel]:
def wrapper():
return self.get_items_from_response(
self.validate_response(
self.client.request("GET", self.api, **self.get_request_args())
self.request_items("GET", self.api, **self.get_request_args())
)
)

Expand Down
69 changes: 63 additions & 6 deletions spiders_for_all/spiders/bilibili/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# 目录

- [目录](#目录)
- [Features](#features)
- [前言](#前言)
- [功能](#功能)
- [快速开始](#快速开始)
- [通过bvid下载视频](#通过bvid下载视频)
- [批量下载视频](#批量下载视频)
- [1. 多个bvid直接传入命令行, 逗号分隔](#1-多个bvid直接传入命令行-逗号分隔)
Expand All @@ -12,16 +12,23 @@
- [根据SQL下载视频](#根据sql下载视频)
- [列出内置的爬虫](#列出内置的爬虫)
- [运行内置爬虫](#运行内置爬虫)
- [Configuration](#configuration)
- [配置](#配置)
- [自定义headers和cookies](#自定义headers和cookies)
- [1. 初始化时设置你自己的headers和cookies](#1-初始化时设置你自己的headers和cookies)
- [2. 在`BaseSpider`爬虫内部设置你自己的headers和cookies](#2-在basespider爬虫内部设置你自己的headers和cookies)
- [3. 在任何进行网络请求的地方设置你自己的headers和cookies](#3-在任何进行网络请求的地方设置你自己的headers和cookies)

# Features
> NOTE:\
> 该仓库的所有模拟请求均未携带`cookie`信息, 都是通过模拟请求头以及请求参数来进行爬取,因此可能会遇到更频繁的风控策略(即-352错误), 不使用`cookie`的主要原因是因为这种方式可能会提高账户被限制的风险, 但是如果你需要指定对应的`cookie`来爬取, 该仓库仍然提供了可拓展的接口进行实现, 详见[自定义headers和cookies](#自定义headers和cookies)
# 功能

- [x] 根据bvid下载视频
- [x] 批量下载视频
- [x] 爬取用户投稿视频(可全部爬取)
- [x] 内置部份分栏爬虫

# 前言
# 快速开始

命令行使用时, 基本的使用格式为:

Expand Down Expand Up @@ -114,7 +121,7 @@ python -m spiders_for_all bilibili run-spider popular -p total 10 -s /tmp

**完整示例见** [所有内置爬虫用法示例](../../../example/bilibili/example_run_spider.sh)

# Configuration
# 配置

你可以通过在当前目录创建`.env`来控制爬虫的一些行为, 针对`bilibili`目前可用的配置为:

Expand All @@ -136,3 +143,53 @@ python -m spiders_for_all bilibili run-spider popular -p total 10 -s /tmp
|REQUEST_RETRY_STEP|int|请求失败后重试间隔递增步长, 单位: 秒, 设置0将以固定的REQUEST_RETRY_INTERVAL进行重试|10|REQUEST_RETRY_STEP=5|
|HTTP_PROXIES|json|代理配置, 格式为json, 详细配置见[requests文档](https://docs.python-requests.org/en/latest/user/advanced/#proxies)|None|HTTP_PROXIES={"http":"http://your_proxy.com"}|

# 自定义headers和cookies

*默认情况下, 所有通过`HttpClient.request`进行的网络请求, 会自动携带`user-agent`, 并且每次请求时都会自动刷新, 该参数由`fake-useragent`库生成的随机ua*

## 1. 初始化时设置你自己的headers和cookies

**初始化设置的headers和cookies会在整个爬虫运行期间保持不变**

```python
from spiders_for_all.core.spider import BaseSpider

class YourSpider(BaseSpider):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.client.headers.update({"your_header_name":"your_header_value"})
self.client.cookies.update({"your_cookie_name":"your_cookie_value"})
```

## 2. 在`BaseSpider`爬虫内部设置你自己的headers和cookies

**通过重写`self.request_items()`来实现:**

```python
from spiders_for_all.core.spider import BaseSpider

class YourSpider(BaseSpider):

def request_items(self, method: str, url: str, **kwargs):

# kwargs的参数会原封不动的传递给requests.request, 你也可以通过直接修改kwargs["headers"]和kwargs["cookies"]来实现

self.client.headers.update({"your_header_name":"your_header_value"})
self.client.cookies.update({"your_cookie_name":"your_cookie_value"})
return super().request_items(method, url, **kwargs)
```

## 3. 在任何进行网络请求的地方设置你自己的headers和cookies

*针对已有的爬虫类进行改动, 需要自行翻阅并修改源码来实现*

```python
from spiders_for_all.core.client import HttpClient
client = HttpClient()
for _ in range(10):
client.headers.update({"your_header_name":"your_header_value"})
client.cookies.update({"your_cookie_name":"your_cookie_value"})
client.request(...)

```

0 comments on commit 951ebc0

Please sign in to comment.