ListPage


NameListPage JSON
Version 1.0.5 PyPI version JSON
download
home_pagehttps://gitee.com/Drission/ListPage
SummaryPage classes dedicated to crawling or manipulating list web pages.
upload_time2024-03-12 14:37:40
maintainer
docs_urlNone
authorg1879
requires_python>=3.6
licenseBSD
keywords page classes
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 简介

***

优雅的列表爬虫。

本库是专门用于爬取或操作列表式网页的页面类,基于 DrissionPage。  
页面类抽象了列表式页面基本特征,封装了常用方法。
只需少量设置即可进行爬取或页面操作,实现可复用、可扩展。  
广泛适用于各种网站的列表页面。  

DrissionPage库:https://gitee.com/g1879/DrissionPage

联系邮箱:g1879@qq.com

# 背景及特性

**背景**

大量的数据用列表页方式存放在网站中,这些列表页有相同的特征,用相同的方法爬取。  
爬取网站时经常重复编写相同的代码,做重复的劳动。  
因此本库把列表页共有的特征提取出来,封装成类,实现可复用。减轻开发的工作量。

**特性**

- 封装常用列表页属性及方法,实现可复用
- 不同类型页面使用相同的操作方式,使用方便
- 可根据特殊情况扩展,实用性强
- 支持控制浏览器和收发数据包方式,并支持无缝切换

**原理**

所有列表页都有共同的特征:**数据行**、**行中的数据列**。能通过 **翻页按钮** 或 **滚动页面** 方式翻页。

只要获取到这几个元素的定位方式,就能封装一个方法实现 **读取 -> 翻页 -> 读取** 的循环操作,直到没有下一页或到达指定页数。

本库支持 xpath 或 css selector 路径,针对不同页面把必要元素路径传递给页面对象,即可实现一行爬取全部页的功能。

# 简单演示

***

一段简单的代码,演示爬取码云推荐项目列表(全部页)。

```python
from ListPage import ListPage, Targets, Xpaths

# 定义页面结构
xpaths = Xpaths()
xpaths.pages_count = '//a[@class="icon item"]/preceding-sibling::a[1]'  # 总页数
xpaths.rows = '//div[@class="project-title"]'  # 行
xpaths.set_col('项目', './/h3/a')  # 列1
xpaths.set_col('星数', './/div[@class="stars-count"]')  # 列2

# 定义目标
targets = Targets(xpaths)
targets.add_target('项目')
targets.add_target('项目', 'href')
targets.add_target('星数')

# 列表第一页
url = 'https://gitee.com/explore/weixin-app?page=1'

p = ListPage(xpaths, url)
p.num_param = 'page'  # url中页面的参数

# 爬取全部页
p.get_list(targets)
```

输出:

```
第1页
https://gitee.com/explore/all
['guanguans/soar-php', 'https://gitee.com/guanguans/soar-php', '6']
...第1页省略部分...
['drinkjava2/jBeanBox', 'https://gitee.com/drinkjava2/jBeanBox', '61']

第2页
https://gitee.com/explore/all?page=2
['pai01234/tokencore', 'https://gitee.com/pai01234/tokencore', '22']
...第2页省略部分...
['docsifyjs/docsify', 'https://gitee.com/docsifyjs/docsify', '47']

...省略下面98页...
```

# 使用方法

***

## 安装及导入

**安装**

```
pip install ListPage
```

**导入**

```python
# 翻页式列表页
from ListPage import ListPage, Paths, Targets

# 滚动式列表页
from ListPage import ScrollingPage, Paths, Targets
```

## 初始化

如只使用 requests 方式爬取,或已在系统变量加入 chrome.exe 和 chromedriver.exe 的路径,可跳过本节。

ListPage 是基于 DrissionPage 实现的,初始化的方法与 DrissionPage 一致,请查看 [DrissionPage 初始化方法]()。

## 定位符

> 了解用法前先了解定位符概念,这个概念是进阶用法,如须快速上手可暂时跳过本节。

有些数据不是储存在元素的文本,而是在元素某个属性中,还可能不是整个字段,而是字段的一部分。因此本库设定了一个定位符格式,用于提取这样的数据。

定位符在定义页面总页数、设置目标时会用到。

示例

```html
<img alt="金刚川" class="board-img" src="https://p1.meituan.net/moviemachine/5cbf9a626b7ed27c96ca3c748655b3ec2550103.jpg@160w_220h_1e_1c">
```

例如猫眼电影榜单中的图片,我们想下载这张图片,就要获取 src 属性,而且要去掉后面 @160w_220h_1e_1c 部分。这个数据的定位符可以这样写:

```python
('封面', 'src', r'(.*)@')
```

定位符由3部分组成

1. 第一部分是元素定位语句,这里的 '封面' 是指在 paths 已定义的 '封面' 列
2. 第二部分是元素的属性名,可省略,省略时默认为 text
3. 第三部分是从元素属性提取内容的正则表达式,可省略,省略时默匹配整个字段

注意,如有第三部分,则第二部分的 'text' 不可省略。

综上所述,定位符有以下形式:

```python
'作者'  # 单个字符串,即('作者', 'text', '(.*)')
('作者')  # 和上一行相同,省略二三部分
('链接', 'href')  # 省略第三部分,即('链接', 'href', '(.*)')
('封面', 'src', r'(.*)@')  # 三部分都写全
```

## Paths 类

Paths 类用于管理关键元素的路径信息。ListPage 创建时须接收记录了页面元素路径的 Paths 对象或字典,用于解析页面。

路径用 xpath 和 css selector 都可以,但一个 Paths 对象保存的路径必须是同一种类的。

**创建 Paths 对象:**

```python
paths = Paths('css')  # 创建类型为css selector的Paths对象
paths = Paths(paths_dict=paths_dict)  # 通过字典创建,字典格式见下文
```

**Paths 类属性:**

```python
# 路径的类型,'css'或'xpath'
paths.type

# 共有的关键元素
paths.rows  # 列表行元素的定位路径,必须
paths.cols  # 行元素中列元素的定位路径,字典格式,必须
paths.next_btn  # 下一页或加载更多按钮元素路径,按页面情况使用,非必须

# 翻页式列表页独有属性
paths.pages_count  # 定位符,总页数所在元素路径,非必须

# 滚动式列表页独有属性
paths.container  # 列表容器,必须
```

**Paths 类方法:**

```python
# 获取某列的路径
paths.get_col(col_name)

# 设置一列路径
paths.set_col(col)

# 设置多列路径
paths.set_col({'col1': 'path1', 'col2': 'path2', ...})  # 用字典设置列
paths.set_col(('col', 'path'))  # 通过一维列表或元组设置列
paths.set_col((('col1', 'path11'), ('col2', 'path2'), ...))  # 通过二维列表或元组设置列

# 从字典读取全部路径设置
paths.from_dict(paths_dict)

# 以字典形式输出保存的路径
paths.as_dict()
```

**通过字典创建**

```python
paths_dict = {
    # 路径的类型,只能是'css'或'xpath',非必须
    'type': 'css',

    # 行元素路径,必须 
    'rows': 'xpath 或 css selector',

    # 列元素相对于行元素的路径,必须
    'cols': {
        'col1': 'xpath 或 css selector',
        'col2': 'xpath 或 css selector',
        ...
    }

    # 翻页式页面总页数获取定位符,格式见上一节,非必须
    'pages_count': 定位符,

    # 下一页(翻页式)或加载更多(滚动式)按钮元素路径,非必须
    'next_btn': 'xpath 或 css selector',

    # 行元素所在容器路径,滚动式页面专用,使用滚动式页面时必须
    'container': 'xpath 或 css selector',
}

paths = Paths(paths_dict=paths_dict)
```

**Tips:** 

- ListPage 不是必须接收 Paths 对象,接收格式正确的字典也是可以的。
- 如果不指定 type,程序会尝试从字符串中判断类型
- 滚动式页面的列路径是相对于 container 的路径的

### Xpaths 类和 CssPaths 类

Xpaths 类和 CssPaths 类是 Paths 类的子类,用法与 Paths 类一致,但其 type 属性是不能改变的。

## Targets 类

Targets 类用于定义爬取目标。  

Targets 对象接收一个 Paths 对象或定义路径的字典,针对列来定义爬取目标。  
每个目标要有一个唯一的名字,内容由一个定位符表示:(列名, [属性名, 正则表达式])  。定位符用法见上文。

示例:

```python
targets.add_targets('项目名', '项目')  # 前一个是目标名称,后一个是列名
targets.add_targets('链接', '项目', 'href')  # 在'项目'列获取href属性定义为链接目标
targets.add_targets('序号', '序号', 'text', '(//d+)')  # 在'序号'列获取数字定义为序号目标
targets.start_stop_row = (1,)  # 爬取第2行到最后一行,规则和切片一致
```

**创建 Targets 对象:**

```python
targets = Targets(paths)  # 创建时要接收一个Paths对象或路径字典,创建这个值后不能修改
targets = Targets(paths, targets_dict)  # 创建时同时接收目标字典,直接创建目标
```

**Targets 类属性:**

```python
targets.paths  # 页面路径管理 Paths 对象
targets.start_stop_row  # 设置爬取列表起止行号
targets.targets  # 返回所有目标组成的字典
```

**Tips:** 有些列表表头表尾不容易通过定位语句和内容区分,因此可设置爬取范围,忽略表头表尾

**Targets 类方法:**

```python
targets.set_targets(targets_dict)  # 通过传入字典批量设置目标
targets.add_target(name, col, attr, re_str)  # 增加单个目标
```

Targets 对象中的目标是针对其保存的 Paths 对象的列设置的。

**通过字典创建**

```python
targets_dict = {
    'start_stop': (1, -1),  # 爬取第2到倒数第2行,规则与切片的一样,非必须
    '目标1': '列1',
    '目标2': ('列2', 'href'),
    '目标3': ('列3', 'src', '(.*)@')
    ...
}

targets = Targets(targets_dict)
```

**start_stop规则**

与切片规则一致,0 为第一个,-1 为最后一个,包含前面的数字,不包含后面的数字。第二个数字可省略,如省略,则爬到最后一行。

示例:

```python
(0, 5)  # 爬取第1行到第4行
(2, -2)  # 爬取第3行到倒数第3行
(1,)  # 爬取第2行到最后一行
(1, None)  # 爬取第2行到最后一行
```

**Tips:** ListPage 不是必须接收 Targets 对象,接收格式正确的字典也是可以的。

## ListPage 类

ListPage 类是翻页式列表页基本类,继承自 DrissionPage 的 MixPage 类。  
专门用于处理翻页式列表页面。如商城产品页、文章列表页。   
它有两种模式,s 模式使用 requests 处理页面,d 模式使用 selenium。  
s 模式效率高,适用于非 js 加载页面数据爬取。  
d 模式可处理 js 加载的页面,可用于自动化操作。  
这两种模式可以互相切换,但要一般没有必要。

**创建 ListPage 对象:**

```python
page = ListPage(paths, index_url, mode, timeout, drission)
'''参数说明
paths: Paths对象或路径字典
index_url: 列表第一页url
mode: 's'使用requests,'d'使用selenium
timeout: s模式时为连接等待时间,d模式时为查找元素等待时间
drission: 驱动器对象,可忽略,详见DrissionPage库
'''
```

**ListPage 属性:**

```python
page.paths  # 页面元素管理对象
page.pages_count  # 总页数
page.current_page_num  # 当前页码
page.num_param  # url中的页码参数
page.step  # 页码步长,配合num_param属性使用
page.first_num  # 第一个页码是0还是1,配合num_param属性使用
```

**ListPage 方法:**

```python
page.to_first_page()  # 跳转到第一页
page.to_next_page(wait)  # 跳转到下一页,然后等待若干秒
page.to_page(num, wait)  # 跳转到任意页,然后等待若干秒
page.get_current_rows()  # 获取当前行元素
page.get_current_list(targets)  # 根据targets中定义的目标获取结果列表
page.get_list(targets, begin, count, stop_when_empty, wait, show_msg, recorder, return_data)
'''参数说明
targets: Targets对象或目标字典
begin: 起始页码
count: 爬取页数
stop_when_empty: 遇到空页是否停止,一般应对无法获取总页数时使用
wait: 翻页后等待秒数
show_msg: 是否实时打印爬取到的信息
recorder: 记录器对象,详见下文
return_data: 是否返回结果,如设置了记录器,不返回结果可以节省内存
'''
```

**Tips:**

- get_list() 是爬取列表页的核心方法
- 用 get_current_rows() 获取到行元素对象可用于自动化操作

**返回的格式**

爬取结果以列表形式呈现,每行数据为一个字典。

```python
[
    {'目标1': '结果1', '目标2': '结果2', ...},
    {'目标1': '结果1', '目标2': '结果2', ...},
    ...
]
```

### 不同列表页的应对方法

总的来说,爬取列表页的思路是:  
**获取总页数** > **爬取一页数据** > **点击下一页按钮或访问下一页链接** > **循环直到最后一页或指定页**

但列表页有多种形态,不一定都提供需要的元素,本库提供灵活的配置,可适应绝大多数列表页的处理。

- **url 带页码信息的列表页**

这种列表页 url 中带页码参数或把路径写在页码中,将其提取出来可大大提高定位页面的效率。

示例:

```
https://gitee.com/explore/all?page=1
https://sz.lianjia.com/ershoufang/pg1/
https://www.procell.com.cn/filters-type-3-p-1.html
https://maoyan.com/board/6?offset=10
```

针对这种页面,可设置 ListPage对象的 num_param 属性。这种方法只适用于页码是有规律数字的情况。  
注意,使用 num_param 时,页面对象的 index_url 属性里也必须包含页码参数。

以上页面的 num_param 设置方法:

```python
# https://gitee.com/explore/all?page=1
page.num_param = 'page'

# https://sz.lianjia.com/ershoufang/pg1/
page.num_param = '/pg'

# https://www.procell.com.cn/filters-type-3-p-1.html
page.num_param = '/filters-type-3-p-'

# https://maoyan.com/board/6?offset=0
page.num_param = 'offset'
page.step = 10
page.first_num = 0
```

可以看出,当页码为 url 后续参数时,直接设置参数名;当是路径一部分时,加上 '/',程序会匹配后续的数字。

注意以上最后一种情况,页码步长为 10,并且以 0 为第一页,因此需要设置 step 和 first_num 两个属性。

设置 num_param 属性后,无须定义下一页按钮的路径即可进行爬取、翻页等操作,程序会用替换数字的方式产生任意页的 url。

- **无法获取总页数的页面**

针对这种页面可指定 pages_count 属性,或在爬取时设置爬取页数。  
如两者都不设置,在爬全部页时,程序直到空页或没有下一页按钮时就会停下。

```python
page.pages_count = 100  # 手动设置总页数
page.get_list(targets, count=100)  # 在爬取时指定爬取页数
```

- **JS 加载的列表页**

这种列表页使用 ajax 获取列表内容,url 不会变化,适合用 d 模式进行爬取。  
d 模式使用 selenium 模拟操作网页,反复点击下一页按钮即可实现翻页。

```python
page = ListPage(xpaths, index_url, 'd')  # 用d模式创建列表页对象
```

- **模式切换**

ListPage 继承自 MixPage,因此也支持 s 模式和 d 模式之间的切换,以及 MixPage 一切功能。

```python
page.change_mod()  # 切换模式
```

MixPage 详情请查看 [DrissionPage 库](https://gitee.com/g1879/DrissionPage)

## ScrollingPage 类

ScrollingPage 类是滚动加载式列表页基本类,继承自 DrissionPage 的 MixPage 类。  
专门用于处理滚动加载式列表页面。如新闻列表页。  
封装了对页面的基本读取和操作方法,只能在 MixPage 的 d 模式下工作。  

**创建 ScrollingPage 类对象**

```python
page = ScrollingPage(paths, index_url, timeout, drission)
```

参数含义与 ListPage 相同,不再赘述。

**ScrollingPage 属性**

```python
page.paths  # 页面元素管理对象
```

**ScrollingPage 方法**

```python
page.to_first_page()  # 重新访问页面,回到首页
page.get_current_rows()  # 获取当前行对象
page.get_current_list(targets, show_msg)  # 根据Targets定义,获取当前页面数据
page.to_next_page(wait)  # 下拉,加载新内容
page.get_new_rows()  # 获取新加载的行对象
page.get_new_list(targets, show_msg)  # 根据Targets定义,获取新加载的数据
page.click_more_btn(wait)  # 点击加载更多按钮(如有定义)
page.get_list(targets, scroll_times, wait, show_msg, recorder, return_data)
'''参数说明
targets: Targets对象或目标字典
scroll_times: 滚动次数
wait: 滚动后等待秒数
show_msg: 是否实时打印爬取到的信息
recorder: 记录器对象,详见下文
return_data: 是否返回结果,如设置了记录器,不返回结果可以节省内存
'''
```

因为无法得知滚动页面的长度,所以滚动页面爬取内容时必须指定滚动次数。

其余用法与 ListPage 类似。

## Recorder 模块

Recorder 对象用于暂缓写入数据,它可接收列表数据,达到一定数量时才一次进行写入,以降低文件读写次数,减少开销。可支持 .csv、.txt、.xlsx、.json 四种格式文件。

详细内容请见:[DataRecorder: 用于记录数据的模块。 (gitee.com)](https://gitee.com/g1879/DataRecorder)

**创建 Recorder 对象**

```python
recorder = Recorder(file_path, cache_size)
```

**Recorder 属性**

```python
recorder.cache_size  # 缓存大小
recorder.file_path  # 文件路径
recorder.encoding  # 编码格式
```

**Recorder 方法**

```python
recorder.add_data(data)  # 添加一批数据,列表或元组格式
recorder.record()  # 将缓存记录到文件然后清空
recorder.set_head(head)  # 设置表头,csv和xlsx格式适用
recorder.set_before(before_col)  # 设置数据前的列,列表、元组或字典格式
recorder.set_after(after_col)  # 设置数据后的列,列表、元组或字典格式
recorder.clear()  # 清空缓存
```

**Tips:** 

- set_before() 和 set_after() 用于添加不是在页面中获取到的数据,通常用于区分多批写入数据,如多次爬取的标识等。示例:爬二手房时各区数据都记录在一个表,就要在爬取到的数据前加一个区列。详见下文示例。
- csv 和 xlsx 写入时会按照结果字典创建表头,如set_before() 和 set_after() 参数也是字典,也可自动写入表头,一般无须 set_head()。
- 除了 xlsx 类型,其余3种类型在程序结束时可自动记录未保存数据,包括因异常结束时。xlsx 须结束前手动调用 record()。

---

# APIs

***

请在 wiki 中查看:[APIs](https://gitee.com/Drission/ListPage/wikis/Home)

            

Raw data

            {
    "_id": null,
    "home_page": "https://gitee.com/Drission/ListPage",
    "name": "ListPage",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "Page classes",
    "author": "g1879",
    "author_email": "g1879@qq.com",
    "download_url": "https://files.pythonhosted.org/packages/ea/a8/9698499cb049e459c399b6f9a303eb6c45cc86b67cadc3f64f85cc343f79/ListPage-1.0.5.tar.gz",
    "platform": null,
    "description": "# \u7b80\u4ecb\r\n\r\n***\r\n\r\n\u4f18\u96c5\u7684\u5217\u8868\u722c\u866b\u3002\r\n\r\n\u672c\u5e93\u662f\u4e13\u95e8\u7528\u4e8e\u722c\u53d6\u6216\u64cd\u4f5c\u5217\u8868\u5f0f\u7f51\u9875\u7684\u9875\u9762\u7c7b\uff0c\u57fa\u4e8e DrissionPage\u3002  \r\n\u9875\u9762\u7c7b\u62bd\u8c61\u4e86\u5217\u8868\u5f0f\u9875\u9762\u57fa\u672c\u7279\u5f81\uff0c\u5c01\u88c5\u4e86\u5e38\u7528\u65b9\u6cd5\u3002\r\n\u53ea\u9700\u5c11\u91cf\u8bbe\u7f6e\u5373\u53ef\u8fdb\u884c\u722c\u53d6\u6216\u9875\u9762\u64cd\u4f5c\uff0c\u5b9e\u73b0\u53ef\u590d\u7528\u3001\u53ef\u6269\u5c55\u3002  \r\n\u5e7f\u6cdb\u9002\u7528\u4e8e\u5404\u79cd\u7f51\u7ad9\u7684\u5217\u8868\u9875\u9762\u3002  \r\n\r\nDrissionPage\u5e93\uff1ahttps://gitee.com/g1879/DrissionPage\r\n\r\n\u8054\u7cfb\u90ae\u7bb1\uff1ag1879@qq.com\r\n\r\n# \u80cc\u666f\u53ca\u7279\u6027\r\n\r\n**\u80cc\u666f**\r\n\r\n\u5927\u91cf\u7684\u6570\u636e\u7528\u5217\u8868\u9875\u65b9\u5f0f\u5b58\u653e\u5728\u7f51\u7ad9\u4e2d\uff0c\u8fd9\u4e9b\u5217\u8868\u9875\u6709\u76f8\u540c\u7684\u7279\u5f81\uff0c\u7528\u76f8\u540c\u7684\u65b9\u6cd5\u722c\u53d6\u3002  \r\n\u722c\u53d6\u7f51\u7ad9\u65f6\u7ecf\u5e38\u91cd\u590d\u7f16\u5199\u76f8\u540c\u7684\u4ee3\u7801\uff0c\u505a\u91cd\u590d\u7684\u52b3\u52a8\u3002  \r\n\u56e0\u6b64\u672c\u5e93\u628a\u5217\u8868\u9875\u5171\u6709\u7684\u7279\u5f81\u63d0\u53d6\u51fa\u6765\uff0c\u5c01\u88c5\u6210\u7c7b\uff0c\u5b9e\u73b0\u53ef\u590d\u7528\u3002\u51cf\u8f7b\u5f00\u53d1\u7684\u5de5\u4f5c\u91cf\u3002\r\n\r\n**\u7279\u6027**\r\n\r\n- \u5c01\u88c5\u5e38\u7528\u5217\u8868\u9875\u5c5e\u6027\u53ca\u65b9\u6cd5\uff0c\u5b9e\u73b0\u53ef\u590d\u7528\r\n- \u4e0d\u540c\u7c7b\u578b\u9875\u9762\u4f7f\u7528\u76f8\u540c\u7684\u64cd\u4f5c\u65b9\u5f0f\uff0c\u4f7f\u7528\u65b9\u4fbf\r\n- \u53ef\u6839\u636e\u7279\u6b8a\u60c5\u51b5\u6269\u5c55\uff0c\u5b9e\u7528\u6027\u5f3a\r\n- \u652f\u6301\u63a7\u5236\u6d4f\u89c8\u5668\u548c\u6536\u53d1\u6570\u636e\u5305\u65b9\u5f0f\uff0c\u5e76\u652f\u6301\u65e0\u7f1d\u5207\u6362\r\n\r\n**\u539f\u7406**\r\n\r\n\u6240\u6709\u5217\u8868\u9875\u90fd\u6709\u5171\u540c\u7684\u7279\u5f81\uff1a**\u6570\u636e\u884c**\u3001**\u884c\u4e2d\u7684\u6570\u636e\u5217**\u3002\u80fd\u901a\u8fc7 **\u7ffb\u9875\u6309\u94ae** \u6216 **\u6eda\u52a8\u9875\u9762** \u65b9\u5f0f\u7ffb\u9875\u3002\r\n\r\n\u53ea\u8981\u83b7\u53d6\u5230\u8fd9\u51e0\u4e2a\u5143\u7d20\u7684\u5b9a\u4f4d\u65b9\u5f0f\uff0c\u5c31\u80fd\u5c01\u88c5\u4e00\u4e2a\u65b9\u6cd5\u5b9e\u73b0 **\u8bfb\u53d6 -> \u7ffb\u9875 -> \u8bfb\u53d6** \u7684\u5faa\u73af\u64cd\u4f5c\uff0c\u76f4\u5230\u6ca1\u6709\u4e0b\u4e00\u9875\u6216\u5230\u8fbe\u6307\u5b9a\u9875\u6570\u3002\r\n\r\n\u672c\u5e93\u652f\u6301 xpath \u6216 css selector \u8def\u5f84\uff0c\u9488\u5bf9\u4e0d\u540c\u9875\u9762\u628a\u5fc5\u8981\u5143\u7d20\u8def\u5f84\u4f20\u9012\u7ed9\u9875\u9762\u5bf9\u8c61\uff0c\u5373\u53ef\u5b9e\u73b0\u4e00\u884c\u722c\u53d6\u5168\u90e8\u9875\u7684\u529f\u80fd\u3002\r\n\r\n# \u7b80\u5355\u6f14\u793a\r\n\r\n***\r\n\r\n\u4e00\u6bb5\u7b80\u5355\u7684\u4ee3\u7801\uff0c\u6f14\u793a\u722c\u53d6\u7801\u4e91\u63a8\u8350\u9879\u76ee\u5217\u8868\uff08\u5168\u90e8\u9875\uff09\u3002\r\n\r\n```python\r\nfrom ListPage import ListPage, Targets, Xpaths\r\n\r\n# \u5b9a\u4e49\u9875\u9762\u7ed3\u6784\r\nxpaths = Xpaths()\r\nxpaths.pages_count = '//a[@class=\"icon item\"]/preceding-sibling::a[1]'  # \u603b\u9875\u6570\r\nxpaths.rows = '//div[@class=\"project-title\"]'  # \u884c\r\nxpaths.set_col('\u9879\u76ee', './/h3/a')  # \u52171\r\nxpaths.set_col('\u661f\u6570', './/div[@class=\"stars-count\"]')  # \u52172\r\n\r\n# \u5b9a\u4e49\u76ee\u6807\r\ntargets = Targets(xpaths)\r\ntargets.add_target('\u9879\u76ee')\r\ntargets.add_target('\u9879\u76ee', 'href')\r\ntargets.add_target('\u661f\u6570')\r\n\r\n# \u5217\u8868\u7b2c\u4e00\u9875\r\nurl = 'https://gitee.com/explore/weixin-app?page=1'\r\n\r\np = ListPage(xpaths, url)\r\np.num_param = 'page'  # url\u4e2d\u9875\u9762\u7684\u53c2\u6570\r\n\r\n# \u722c\u53d6\u5168\u90e8\u9875\r\np.get_list(targets)\r\n```\r\n\r\n\u8f93\u51fa\uff1a\r\n\r\n```\r\n\u7b2c1\u9875\r\nhttps://gitee.com/explore/all\r\n['guanguans/soar-php', 'https://gitee.com/guanguans/soar-php', '6']\r\n...\u7b2c1\u9875\u7701\u7565\u90e8\u5206...\r\n['drinkjava2/jBeanBox', 'https://gitee.com/drinkjava2/jBeanBox', '61']\r\n\r\n\u7b2c2\u9875\r\nhttps://gitee.com/explore/all?page=2\r\n['pai01234/tokencore', 'https://gitee.com/pai01234/tokencore', '22']\r\n...\u7b2c2\u9875\u7701\u7565\u90e8\u5206...\r\n['docsifyjs/docsify', 'https://gitee.com/docsifyjs/docsify', '47']\r\n\r\n...\u7701\u7565\u4e0b\u976298\u9875...\r\n```\r\n\r\n# \u4f7f\u7528\u65b9\u6cd5\r\n\r\n***\r\n\r\n## \u5b89\u88c5\u53ca\u5bfc\u5165\r\n\r\n**\u5b89\u88c5**\r\n\r\n```\r\npip install ListPage\r\n```\r\n\r\n**\u5bfc\u5165**\r\n\r\n```python\r\n# \u7ffb\u9875\u5f0f\u5217\u8868\u9875\r\nfrom ListPage import ListPage, Paths, Targets\r\n\r\n# \u6eda\u52a8\u5f0f\u5217\u8868\u9875\r\nfrom ListPage import ScrollingPage, Paths, Targets\r\n```\r\n\r\n## \u521d\u59cb\u5316\r\n\r\n\u5982\u53ea\u4f7f\u7528 requests \u65b9\u5f0f\u722c\u53d6\uff0c\u6216\u5df2\u5728\u7cfb\u7edf\u53d8\u91cf\u52a0\u5165 chrome.exe \u548c chromedriver.exe \u7684\u8def\u5f84\uff0c\u53ef\u8df3\u8fc7\u672c\u8282\u3002\r\n\r\nListPage \u662f\u57fa\u4e8e DrissionPage \u5b9e\u73b0\u7684\uff0c\u521d\u59cb\u5316\u7684\u65b9\u6cd5\u4e0e DrissionPage \u4e00\u81f4\uff0c\u8bf7\u67e5\u770b [DrissionPage \u521d\u59cb\u5316\u65b9\u6cd5]()\u3002\r\n\r\n## \u5b9a\u4f4d\u7b26\r\n\r\n> \u4e86\u89e3\u7528\u6cd5\u524d\u5148\u4e86\u89e3\u5b9a\u4f4d\u7b26\u6982\u5ff5\uff0c\u8fd9\u4e2a\u6982\u5ff5\u662f\u8fdb\u9636\u7528\u6cd5\uff0c\u5982\u987b\u5feb\u901f\u4e0a\u624b\u53ef\u6682\u65f6\u8df3\u8fc7\u672c\u8282\u3002\r\n\r\n\u6709\u4e9b\u6570\u636e\u4e0d\u662f\u50a8\u5b58\u5728\u5143\u7d20\u7684\u6587\u672c\uff0c\u800c\u662f\u5728\u5143\u7d20\u67d0\u4e2a\u5c5e\u6027\u4e2d\uff0c\u8fd8\u53ef\u80fd\u4e0d\u662f\u6574\u4e2a\u5b57\u6bb5\uff0c\u800c\u662f\u5b57\u6bb5\u7684\u4e00\u90e8\u5206\u3002\u56e0\u6b64\u672c\u5e93\u8bbe\u5b9a\u4e86\u4e00\u4e2a\u5b9a\u4f4d\u7b26\u683c\u5f0f\uff0c\u7528\u4e8e\u63d0\u53d6\u8fd9\u6837\u7684\u6570\u636e\u3002\r\n\r\n\u5b9a\u4f4d\u7b26\u5728\u5b9a\u4e49\u9875\u9762\u603b\u9875\u6570\u3001\u8bbe\u7f6e\u76ee\u6807\u65f6\u4f1a\u7528\u5230\u3002\r\n\r\n\u793a\u4f8b\r\n\r\n```html\r\n<img alt=\"\u91d1\u521a\u5ddd\" class=\"board-img\" src=\"https://p1.meituan.net/moviemachine/5cbf9a626b7ed27c96ca3c748655b3ec2550103.jpg@160w_220h_1e_1c\">\r\n```\r\n\r\n\u4f8b\u5982\u732b\u773c\u7535\u5f71\u699c\u5355\u4e2d\u7684\u56fe\u7247\uff0c\u6211\u4eec\u60f3\u4e0b\u8f7d\u8fd9\u5f20\u56fe\u7247\uff0c\u5c31\u8981\u83b7\u53d6 src \u5c5e\u6027\uff0c\u800c\u4e14\u8981\u53bb\u6389\u540e\u9762 @160w_220h_1e_1c \u90e8\u5206\u3002\u8fd9\u4e2a\u6570\u636e\u7684\u5b9a\u4f4d\u7b26\u53ef\u4ee5\u8fd9\u6837\u5199\uff1a\r\n\r\n```python\r\n('\u5c01\u9762', 'src', r'(.*)@')\r\n```\r\n\r\n\u5b9a\u4f4d\u7b26\u75313\u90e8\u5206\u7ec4\u6210\r\n\r\n1. \u7b2c\u4e00\u90e8\u5206\u662f\u5143\u7d20\u5b9a\u4f4d\u8bed\u53e5\uff0c\u8fd9\u91cc\u7684 '\u5c01\u9762' \u662f\u6307\u5728 paths \u5df2\u5b9a\u4e49\u7684 '\u5c01\u9762' \u5217\r\n2. \u7b2c\u4e8c\u90e8\u5206\u662f\u5143\u7d20\u7684\u5c5e\u6027\u540d\uff0c\u53ef\u7701\u7565\uff0c\u7701\u7565\u65f6\u9ed8\u8ba4\u4e3a text\r\n3. \u7b2c\u4e09\u90e8\u5206\u662f\u4ece\u5143\u7d20\u5c5e\u6027\u63d0\u53d6\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u53ef\u7701\u7565\uff0c\u7701\u7565\u65f6\u9ed8\u5339\u914d\u6574\u4e2a\u5b57\u6bb5\r\n\r\n\u6ce8\u610f\uff0c\u5982\u6709\u7b2c\u4e09\u90e8\u5206\uff0c\u5219\u7b2c\u4e8c\u90e8\u5206\u7684 'text' \u4e0d\u53ef\u7701\u7565\u3002\r\n\r\n\u7efc\u4e0a\u6240\u8ff0\uff0c\u5b9a\u4f4d\u7b26\u6709\u4ee5\u4e0b\u5f62\u5f0f\uff1a\r\n\r\n```python\r\n'\u4f5c\u8005'  # \u5355\u4e2a\u5b57\u7b26\u4e32\uff0c\u5373('\u4f5c\u8005', 'text', '(.*)')\r\n('\u4f5c\u8005')  # \u548c\u4e0a\u4e00\u884c\u76f8\u540c\uff0c\u7701\u7565\u4e8c\u4e09\u90e8\u5206\r\n('\u94fe\u63a5', 'href')  # \u7701\u7565\u7b2c\u4e09\u90e8\u5206\uff0c\u5373('\u94fe\u63a5', 'href', '(.*)')\r\n('\u5c01\u9762', 'src', r'(.*)@')  # \u4e09\u90e8\u5206\u90fd\u5199\u5168\r\n```\r\n\r\n## Paths \u7c7b\r\n\r\nPaths \u7c7b\u7528\u4e8e\u7ba1\u7406\u5173\u952e\u5143\u7d20\u7684\u8def\u5f84\u4fe1\u606f\u3002ListPage \u521b\u5efa\u65f6\u987b\u63a5\u6536\u8bb0\u5f55\u4e86\u9875\u9762\u5143\u7d20\u8def\u5f84\u7684 Paths \u5bf9\u8c61\u6216\u5b57\u5178\uff0c\u7528\u4e8e\u89e3\u6790\u9875\u9762\u3002\r\n\r\n\u8def\u5f84\u7528 xpath \u548c css selector \u90fd\u53ef\u4ee5\uff0c\u4f46\u4e00\u4e2a Paths \u5bf9\u8c61\u4fdd\u5b58\u7684\u8def\u5f84\u5fc5\u987b\u662f\u540c\u4e00\u79cd\u7c7b\u7684\u3002\r\n\r\n**\u521b\u5efa Paths \u5bf9\u8c61\uff1a**\r\n\r\n```python\r\npaths = Paths('css')  # \u521b\u5efa\u7c7b\u578b\u4e3acss selector\u7684Paths\u5bf9\u8c61\r\npaths = Paths(paths_dict=paths_dict)  # \u901a\u8fc7\u5b57\u5178\u521b\u5efa\uff0c\u5b57\u5178\u683c\u5f0f\u89c1\u4e0b\u6587\r\n```\r\n\r\n**Paths \u7c7b\u5c5e\u6027\uff1a**\r\n\r\n```python\r\n# \u8def\u5f84\u7684\u7c7b\u578b\uff0c'css'\u6216'xpath'\r\npaths.type\r\n\r\n# \u5171\u6709\u7684\u5173\u952e\u5143\u7d20\r\npaths.rows  # \u5217\u8868\u884c\u5143\u7d20\u7684\u5b9a\u4f4d\u8def\u5f84\uff0c\u5fc5\u987b\r\npaths.cols  # \u884c\u5143\u7d20\u4e2d\u5217\u5143\u7d20\u7684\u5b9a\u4f4d\u8def\u5f84\uff0c\u5b57\u5178\u683c\u5f0f\uff0c\u5fc5\u987b\r\npaths.next_btn  # \u4e0b\u4e00\u9875\u6216\u52a0\u8f7d\u66f4\u591a\u6309\u94ae\u5143\u7d20\u8def\u5f84\uff0c\u6309\u9875\u9762\u60c5\u51b5\u4f7f\u7528\uff0c\u975e\u5fc5\u987b\r\n\r\n# \u7ffb\u9875\u5f0f\u5217\u8868\u9875\u72ec\u6709\u5c5e\u6027\r\npaths.pages_count  # \u5b9a\u4f4d\u7b26\uff0c\u603b\u9875\u6570\u6240\u5728\u5143\u7d20\u8def\u5f84\uff0c\u975e\u5fc5\u987b\r\n\r\n# \u6eda\u52a8\u5f0f\u5217\u8868\u9875\u72ec\u6709\u5c5e\u6027\r\npaths.container  # \u5217\u8868\u5bb9\u5668\uff0c\u5fc5\u987b\r\n```\r\n\r\n**Paths \u7c7b\u65b9\u6cd5\uff1a**\r\n\r\n```python\r\n# \u83b7\u53d6\u67d0\u5217\u7684\u8def\u5f84\r\npaths.get_col(col_name)\r\n\r\n# \u8bbe\u7f6e\u4e00\u5217\u8def\u5f84\r\npaths.set_col(col)\r\n\r\n# \u8bbe\u7f6e\u591a\u5217\u8def\u5f84\r\npaths.set_col({'col1': 'path1', 'col2': 'path2', ...})  # \u7528\u5b57\u5178\u8bbe\u7f6e\u5217\r\npaths.set_col(('col', 'path'))  # \u901a\u8fc7\u4e00\u7ef4\u5217\u8868\u6216\u5143\u7ec4\u8bbe\u7f6e\u5217\r\npaths.set_col((('col1', 'path11'), ('col2', 'path2'), ...))  # \u901a\u8fc7\u4e8c\u7ef4\u5217\u8868\u6216\u5143\u7ec4\u8bbe\u7f6e\u5217\r\n\r\n# \u4ece\u5b57\u5178\u8bfb\u53d6\u5168\u90e8\u8def\u5f84\u8bbe\u7f6e\r\npaths.from_dict(paths_dict)\r\n\r\n# \u4ee5\u5b57\u5178\u5f62\u5f0f\u8f93\u51fa\u4fdd\u5b58\u7684\u8def\u5f84\r\npaths.as_dict()\r\n```\r\n\r\n**\u901a\u8fc7\u5b57\u5178\u521b\u5efa**\r\n\r\n```python\r\npaths_dict = {\r\n    # \u8def\u5f84\u7684\u7c7b\u578b\uff0c\u53ea\u80fd\u662f'css'\u6216'xpath'\uff0c\u975e\u5fc5\u987b\r\n    'type': 'css',\r\n\r\n    # \u884c\u5143\u7d20\u8def\u5f84\uff0c\u5fc5\u987b \r\n    'rows': 'xpath \u6216 css selector',\r\n\r\n    # \u5217\u5143\u7d20\u76f8\u5bf9\u4e8e\u884c\u5143\u7d20\u7684\u8def\u5f84\uff0c\u5fc5\u987b\r\n    'cols': {\r\n        'col1': 'xpath \u6216 css selector',\r\n        'col2': 'xpath \u6216 css selector',\r\n        ...\r\n    }\r\n\r\n    # \u7ffb\u9875\u5f0f\u9875\u9762\u603b\u9875\u6570\u83b7\u53d6\u5b9a\u4f4d\u7b26\uff0c\u683c\u5f0f\u89c1\u4e0a\u4e00\u8282\uff0c\u975e\u5fc5\u987b\r\n    'pages_count': \u5b9a\u4f4d\u7b26,\r\n\r\n    # \u4e0b\u4e00\u9875\uff08\u7ffb\u9875\u5f0f\uff09\u6216\u52a0\u8f7d\u66f4\u591a\uff08\u6eda\u52a8\u5f0f\uff09\u6309\u94ae\u5143\u7d20\u8def\u5f84\uff0c\u975e\u5fc5\u987b\r\n    'next_btn': 'xpath \u6216 css selector',\r\n\r\n    # \u884c\u5143\u7d20\u6240\u5728\u5bb9\u5668\u8def\u5f84\uff0c\u6eda\u52a8\u5f0f\u9875\u9762\u4e13\u7528\uff0c\u4f7f\u7528\u6eda\u52a8\u5f0f\u9875\u9762\u65f6\u5fc5\u987b\r\n    'container': 'xpath \u6216 css selector',\r\n}\r\n\r\npaths = Paths(paths_dict=paths_dict)\r\n```\r\n\r\n**Tips\uff1a** \r\n\r\n- ListPage \u4e0d\u662f\u5fc5\u987b\u63a5\u6536 Paths \u5bf9\u8c61\uff0c\u63a5\u6536\u683c\u5f0f\u6b63\u786e\u7684\u5b57\u5178\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\r\n- \u5982\u679c\u4e0d\u6307\u5b9a type\uff0c\u7a0b\u5e8f\u4f1a\u5c1d\u8bd5\u4ece\u5b57\u7b26\u4e32\u4e2d\u5224\u65ad\u7c7b\u578b\r\n- \u6eda\u52a8\u5f0f\u9875\u9762\u7684\u5217\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e container \u7684\u8def\u5f84\u7684\r\n\r\n### Xpaths \u7c7b\u548c CssPaths \u7c7b\r\n\r\nXpaths \u7c7b\u548c CssPaths \u7c7b\u662f Paths \u7c7b\u7684\u5b50\u7c7b\uff0c\u7528\u6cd5\u4e0e Paths \u7c7b\u4e00\u81f4\uff0c\u4f46\u5176 type \u5c5e\u6027\u662f\u4e0d\u80fd\u6539\u53d8\u7684\u3002\r\n\r\n## Targets \u7c7b\r\n\r\nTargets \u7c7b\u7528\u4e8e\u5b9a\u4e49\u722c\u53d6\u76ee\u6807\u3002  \r\n\r\nTargets \u5bf9\u8c61\u63a5\u6536\u4e00\u4e2a Paths \u5bf9\u8c61\u6216\u5b9a\u4e49\u8def\u5f84\u7684\u5b57\u5178\uff0c\u9488\u5bf9\u5217\u6765\u5b9a\u4e49\u722c\u53d6\u76ee\u6807\u3002  \r\n\u6bcf\u4e2a\u76ee\u6807\u8981\u6709\u4e00\u4e2a\u552f\u4e00\u7684\u540d\u5b57\uff0c\u5185\u5bb9\u7531\u4e00\u4e2a\u5b9a\u4f4d\u7b26\u8868\u793a\uff1a(\u5217\u540d, [\u5c5e\u6027\u540d, \u6b63\u5219\u8868\u8fbe\u5f0f])  \u3002\u5b9a\u4f4d\u7b26\u7528\u6cd5\u89c1\u4e0a\u6587\u3002\r\n\r\n\u793a\u4f8b\uff1a\r\n\r\n```python\r\ntargets.add_targets('\u9879\u76ee\u540d', '\u9879\u76ee')  # \u524d\u4e00\u4e2a\u662f\u76ee\u6807\u540d\u79f0\uff0c\u540e\u4e00\u4e2a\u662f\u5217\u540d\r\ntargets.add_targets('\u94fe\u63a5', '\u9879\u76ee', 'href')  # \u5728'\u9879\u76ee'\u5217\u83b7\u53d6href\u5c5e\u6027\u5b9a\u4e49\u4e3a\u94fe\u63a5\u76ee\u6807\r\ntargets.add_targets('\u5e8f\u53f7', '\u5e8f\u53f7', 'text', '(//d+)')  # \u5728'\u5e8f\u53f7'\u5217\u83b7\u53d6\u6570\u5b57\u5b9a\u4e49\u4e3a\u5e8f\u53f7\u76ee\u6807\r\ntargets.start_stop_row = (1,)  # \u722c\u53d6\u7b2c2\u884c\u5230\u6700\u540e\u4e00\u884c\uff0c\u89c4\u5219\u548c\u5207\u7247\u4e00\u81f4\r\n```\r\n\r\n**\u521b\u5efa Targets \u5bf9\u8c61\uff1a**\r\n\r\n```python\r\ntargets = Targets(paths)  # \u521b\u5efa\u65f6\u8981\u63a5\u6536\u4e00\u4e2aPaths\u5bf9\u8c61\u6216\u8def\u5f84\u5b57\u5178\uff0c\u521b\u5efa\u8fd9\u4e2a\u503c\u540e\u4e0d\u80fd\u4fee\u6539\r\ntargets = Targets(paths, targets_dict)  # \u521b\u5efa\u65f6\u540c\u65f6\u63a5\u6536\u76ee\u6807\u5b57\u5178\uff0c\u76f4\u63a5\u521b\u5efa\u76ee\u6807\r\n```\r\n\r\n**Targets \u7c7b\u5c5e\u6027\uff1a**\r\n\r\n```python\r\ntargets.paths  # \u9875\u9762\u8def\u5f84\u7ba1\u7406 Paths \u5bf9\u8c61\r\ntargets.start_stop_row  # \u8bbe\u7f6e\u722c\u53d6\u5217\u8868\u8d77\u6b62\u884c\u53f7\r\ntargets.targets  # \u8fd4\u56de\u6240\u6709\u76ee\u6807\u7ec4\u6210\u7684\u5b57\u5178\r\n```\r\n\r\n**Tips\uff1a** \u6709\u4e9b\u5217\u8868\u8868\u5934\u8868\u5c3e\u4e0d\u5bb9\u6613\u901a\u8fc7\u5b9a\u4f4d\u8bed\u53e5\u548c\u5185\u5bb9\u533a\u5206\uff0c\u56e0\u6b64\u53ef\u8bbe\u7f6e\u722c\u53d6\u8303\u56f4\uff0c\u5ffd\u7565\u8868\u5934\u8868\u5c3e\r\n\r\n**Targets \u7c7b\u65b9\u6cd5\uff1a**\r\n\r\n```python\r\ntargets.set_targets(targets_dict)  # \u901a\u8fc7\u4f20\u5165\u5b57\u5178\u6279\u91cf\u8bbe\u7f6e\u76ee\u6807\r\ntargets.add_target(name, col, attr, re_str)  # \u589e\u52a0\u5355\u4e2a\u76ee\u6807\r\n```\r\n\r\nTargets \u5bf9\u8c61\u4e2d\u7684\u76ee\u6807\u662f\u9488\u5bf9\u5176\u4fdd\u5b58\u7684 Paths \u5bf9\u8c61\u7684\u5217\u8bbe\u7f6e\u7684\u3002\r\n\r\n**\u901a\u8fc7\u5b57\u5178\u521b\u5efa**\r\n\r\n```python\r\ntargets_dict = {\r\n    'start_stop': (1, -1),  # \u722c\u53d6\u7b2c2\u5230\u5012\u6570\u7b2c2\u884c\uff0c\u89c4\u5219\u4e0e\u5207\u7247\u7684\u4e00\u6837\uff0c\u975e\u5fc5\u987b\r\n    '\u76ee\u68071': '\u52171',\r\n    '\u76ee\u68072': ('\u52172', 'href'),\r\n    '\u76ee\u68073': ('\u52173', 'src', '(.*)@')\r\n    ...\r\n}\r\n\r\ntargets = Targets(targets_dict)\r\n```\r\n\r\n**start_stop\u89c4\u5219**\r\n\r\n\u4e0e\u5207\u7247\u89c4\u5219\u4e00\u81f4\uff0c0 \u4e3a\u7b2c\u4e00\u4e2a\uff0c-1 \u4e3a\u6700\u540e\u4e00\u4e2a\uff0c\u5305\u542b\u524d\u9762\u7684\u6570\u5b57\uff0c\u4e0d\u5305\u542b\u540e\u9762\u7684\u6570\u5b57\u3002\u7b2c\u4e8c\u4e2a\u6570\u5b57\u53ef\u7701\u7565\uff0c\u5982\u7701\u7565\uff0c\u5219\u722c\u5230\u6700\u540e\u4e00\u884c\u3002\r\n\r\n\u793a\u4f8b\uff1a\r\n\r\n```python\r\n(0, 5)  # \u722c\u53d6\u7b2c1\u884c\u5230\u7b2c4\u884c\r\n(2, -2)  # \u722c\u53d6\u7b2c3\u884c\u5230\u5012\u6570\u7b2c3\u884c\r\n(1,)  # \u722c\u53d6\u7b2c2\u884c\u5230\u6700\u540e\u4e00\u884c\r\n(1, None)  # \u722c\u53d6\u7b2c2\u884c\u5230\u6700\u540e\u4e00\u884c\r\n```\r\n\r\n**Tips\uff1a** ListPage \u4e0d\u662f\u5fc5\u987b\u63a5\u6536 Targets \u5bf9\u8c61\uff0c\u63a5\u6536\u683c\u5f0f\u6b63\u786e\u7684\u5b57\u5178\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\r\n\r\n## ListPage \u7c7b\r\n\r\nListPage \u7c7b\u662f\u7ffb\u9875\u5f0f\u5217\u8868\u9875\u57fa\u672c\u7c7b\uff0c\u7ee7\u627f\u81ea DrissionPage \u7684 MixPage \u7c7b\u3002  \r\n\u4e13\u95e8\u7528\u4e8e\u5904\u7406\u7ffb\u9875\u5f0f\u5217\u8868\u9875\u9762\u3002\u5982\u5546\u57ce\u4ea7\u54c1\u9875\u3001\u6587\u7ae0\u5217\u8868\u9875\u3002   \r\n\u5b83\u6709\u4e24\u79cd\u6a21\u5f0f\uff0cs \u6a21\u5f0f\u4f7f\u7528 requests \u5904\u7406\u9875\u9762\uff0cd \u6a21\u5f0f\u4f7f\u7528 selenium\u3002  \r\ns \u6a21\u5f0f\u6548\u7387\u9ad8\uff0c\u9002\u7528\u4e8e\u975e js \u52a0\u8f7d\u9875\u9762\u6570\u636e\u722c\u53d6\u3002  \r\nd \u6a21\u5f0f\u53ef\u5904\u7406 js \u52a0\u8f7d\u7684\u9875\u9762\uff0c\u53ef\u7528\u4e8e\u81ea\u52a8\u5316\u64cd\u4f5c\u3002  \r\n\u8fd9\u4e24\u79cd\u6a21\u5f0f\u53ef\u4ee5\u4e92\u76f8\u5207\u6362\uff0c\u4f46\u8981\u4e00\u822c\u6ca1\u6709\u5fc5\u8981\u3002\r\n\r\n**\u521b\u5efa ListPage \u5bf9\u8c61\uff1a**\r\n\r\n```python\r\npage = ListPage(paths, index_url, mode, timeout, drission)\r\n'''\u53c2\u6570\u8bf4\u660e\r\npaths: Paths\u5bf9\u8c61\u6216\u8def\u5f84\u5b57\u5178\r\nindex_url: \u5217\u8868\u7b2c\u4e00\u9875url\r\nmode: 's'\u4f7f\u7528requests\uff0c'd'\u4f7f\u7528selenium\r\ntimeout: s\u6a21\u5f0f\u65f6\u4e3a\u8fde\u63a5\u7b49\u5f85\u65f6\u95f4\uff0cd\u6a21\u5f0f\u65f6\u4e3a\u67e5\u627e\u5143\u7d20\u7b49\u5f85\u65f6\u95f4\r\ndrission: \u9a71\u52a8\u5668\u5bf9\u8c61\uff0c\u53ef\u5ffd\u7565\uff0c\u8be6\u89c1DrissionPage\u5e93\r\n'''\r\n```\r\n\r\n**ListPage \u5c5e\u6027\uff1a**\r\n\r\n```python\r\npage.paths  # \u9875\u9762\u5143\u7d20\u7ba1\u7406\u5bf9\u8c61\r\npage.pages_count  # \u603b\u9875\u6570\r\npage.current_page_num  # \u5f53\u524d\u9875\u7801\r\npage.num_param  # url\u4e2d\u7684\u9875\u7801\u53c2\u6570\r\npage.step  # \u9875\u7801\u6b65\u957f\uff0c\u914d\u5408num_param\u5c5e\u6027\u4f7f\u7528\r\npage.first_num  # \u7b2c\u4e00\u4e2a\u9875\u7801\u662f0\u8fd8\u662f1\uff0c\u914d\u5408num_param\u5c5e\u6027\u4f7f\u7528\r\n```\r\n\r\n**ListPage \u65b9\u6cd5\uff1a**\r\n\r\n```python\r\npage.to_first_page()  # \u8df3\u8f6c\u5230\u7b2c\u4e00\u9875\r\npage.to_next_page(wait)  # \u8df3\u8f6c\u5230\u4e0b\u4e00\u9875\uff0c\u7136\u540e\u7b49\u5f85\u82e5\u5e72\u79d2\r\npage.to_page(num, wait)  # \u8df3\u8f6c\u5230\u4efb\u610f\u9875\uff0c\u7136\u540e\u7b49\u5f85\u82e5\u5e72\u79d2\r\npage.get_current_rows()  # \u83b7\u53d6\u5f53\u524d\u884c\u5143\u7d20\r\npage.get_current_list(targets)  # \u6839\u636etargets\u4e2d\u5b9a\u4e49\u7684\u76ee\u6807\u83b7\u53d6\u7ed3\u679c\u5217\u8868\r\npage.get_list(targets, begin, count, stop_when_empty, wait, show_msg, recorder, return_data)\r\n'''\u53c2\u6570\u8bf4\u660e\r\ntargets: Targets\u5bf9\u8c61\u6216\u76ee\u6807\u5b57\u5178\r\nbegin: \u8d77\u59cb\u9875\u7801\r\ncount: \u722c\u53d6\u9875\u6570\r\nstop_when_empty: \u9047\u5230\u7a7a\u9875\u662f\u5426\u505c\u6b62\uff0c\u4e00\u822c\u5e94\u5bf9\u65e0\u6cd5\u83b7\u53d6\u603b\u9875\u6570\u65f6\u4f7f\u7528\r\nwait: \u7ffb\u9875\u540e\u7b49\u5f85\u79d2\u6570\r\nshow_msg: \u662f\u5426\u5b9e\u65f6\u6253\u5370\u722c\u53d6\u5230\u7684\u4fe1\u606f\r\nrecorder: \u8bb0\u5f55\u5668\u5bf9\u8c61\uff0c\u8be6\u89c1\u4e0b\u6587\r\nreturn_data: \u662f\u5426\u8fd4\u56de\u7ed3\u679c\uff0c\u5982\u8bbe\u7f6e\u4e86\u8bb0\u5f55\u5668\uff0c\u4e0d\u8fd4\u56de\u7ed3\u679c\u53ef\u4ee5\u8282\u7701\u5185\u5b58\r\n'''\r\n```\r\n\r\n**Tips:**\r\n\r\n- get_list() \u662f\u722c\u53d6\u5217\u8868\u9875\u7684\u6838\u5fc3\u65b9\u6cd5\r\n- \u7528 get_current_rows() \u83b7\u53d6\u5230\u884c\u5143\u7d20\u5bf9\u8c61\u53ef\u7528\u4e8e\u81ea\u52a8\u5316\u64cd\u4f5c\r\n\r\n**\u8fd4\u56de\u7684\u683c\u5f0f**\r\n\r\n\u722c\u53d6\u7ed3\u679c\u4ee5\u5217\u8868\u5f62\u5f0f\u5448\u73b0\uff0c\u6bcf\u884c\u6570\u636e\u4e3a\u4e00\u4e2a\u5b57\u5178\u3002\r\n\r\n```python\r\n[\r\n    {'\u76ee\u68071': '\u7ed3\u679c1', '\u76ee\u68072': '\u7ed3\u679c2', ...},\r\n    {'\u76ee\u68071': '\u7ed3\u679c1', '\u76ee\u68072': '\u7ed3\u679c2', ...},\r\n    ...\r\n]\r\n```\r\n\r\n### \u4e0d\u540c\u5217\u8868\u9875\u7684\u5e94\u5bf9\u65b9\u6cd5\r\n\r\n\u603b\u7684\u6765\u8bf4\uff0c\u722c\u53d6\u5217\u8868\u9875\u7684\u601d\u8def\u662f\uff1a  \r\n**\u83b7\u53d6\u603b\u9875\u6570** > **\u722c\u53d6\u4e00\u9875\u6570\u636e** > **\u70b9\u51fb\u4e0b\u4e00\u9875\u6309\u94ae\u6216\u8bbf\u95ee\u4e0b\u4e00\u9875\u94fe\u63a5** > **\u5faa\u73af\u76f4\u5230\u6700\u540e\u4e00\u9875\u6216\u6307\u5b9a\u9875**\r\n\r\n\u4f46\u5217\u8868\u9875\u6709\u591a\u79cd\u5f62\u6001\uff0c\u4e0d\u4e00\u5b9a\u90fd\u63d0\u4f9b\u9700\u8981\u7684\u5143\u7d20\uff0c\u672c\u5e93\u63d0\u4f9b\u7075\u6d3b\u7684\u914d\u7f6e\uff0c\u53ef\u9002\u5e94\u7edd\u5927\u591a\u6570\u5217\u8868\u9875\u7684\u5904\u7406\u3002\r\n\r\n- **url \u5e26\u9875\u7801\u4fe1\u606f\u7684\u5217\u8868\u9875**\r\n\r\n\u8fd9\u79cd\u5217\u8868\u9875 url \u4e2d\u5e26\u9875\u7801\u53c2\u6570\u6216\u628a\u8def\u5f84\u5199\u5728\u9875\u7801\u4e2d\uff0c\u5c06\u5176\u63d0\u53d6\u51fa\u6765\u53ef\u5927\u5927\u63d0\u9ad8\u5b9a\u4f4d\u9875\u9762\u7684\u6548\u7387\u3002\r\n\r\n\u793a\u4f8b\uff1a\r\n\r\n```\r\nhttps://gitee.com/explore/all?page=1\r\nhttps://sz.lianjia.com/ershoufang/pg1/\r\nhttps://www.procell.com.cn/filters-type-3-p-1.html\r\nhttps://maoyan.com/board/6?offset=10\r\n```\r\n\r\n\u9488\u5bf9\u8fd9\u79cd\u9875\u9762\uff0c\u53ef\u8bbe\u7f6e ListPage\u5bf9\u8c61\u7684 num_param \u5c5e\u6027\u3002\u8fd9\u79cd\u65b9\u6cd5\u53ea\u9002\u7528\u4e8e\u9875\u7801\u662f\u6709\u89c4\u5f8b\u6570\u5b57\u7684\u60c5\u51b5\u3002  \r\n\u6ce8\u610f\uff0c\u4f7f\u7528 num_param \u65f6\uff0c\u9875\u9762\u5bf9\u8c61\u7684 index_url \u5c5e\u6027\u91cc\u4e5f\u5fc5\u987b\u5305\u542b\u9875\u7801\u53c2\u6570\u3002\r\n\r\n\u4ee5\u4e0a\u9875\u9762\u7684 num_param \u8bbe\u7f6e\u65b9\u6cd5\uff1a\r\n\r\n```python\r\n# https://gitee.com/explore/all?page=1\r\npage.num_param = 'page'\r\n\r\n# https://sz.lianjia.com/ershoufang/pg1/\r\npage.num_param = '/pg'\r\n\r\n# https://www.procell.com.cn/filters-type-3-p-1.html\r\npage.num_param = '/filters-type-3-p-'\r\n\r\n# https://maoyan.com/board/6?offset=0\r\npage.num_param = 'offset'\r\npage.step = 10\r\npage.first_num = 0\r\n```\r\n\r\n\u53ef\u4ee5\u770b\u51fa\uff0c\u5f53\u9875\u7801\u4e3a url \u540e\u7eed\u53c2\u6570\u65f6\uff0c\u76f4\u63a5\u8bbe\u7f6e\u53c2\u6570\u540d\uff1b\u5f53\u662f\u8def\u5f84\u4e00\u90e8\u5206\u65f6\uff0c\u52a0\u4e0a '/'\uff0c\u7a0b\u5e8f\u4f1a\u5339\u914d\u540e\u7eed\u7684\u6570\u5b57\u3002\r\n\r\n\u6ce8\u610f\u4ee5\u4e0a\u6700\u540e\u4e00\u79cd\u60c5\u51b5\uff0c\u9875\u7801\u6b65\u957f\u4e3a 10\uff0c\u5e76\u4e14\u4ee5 0 \u4e3a\u7b2c\u4e00\u9875\uff0c\u56e0\u6b64\u9700\u8981\u8bbe\u7f6e step \u548c first_num \u4e24\u4e2a\u5c5e\u6027\u3002\r\n\r\n\u8bbe\u7f6e num_param \u5c5e\u6027\u540e\uff0c\u65e0\u987b\u5b9a\u4e49\u4e0b\u4e00\u9875\u6309\u94ae\u7684\u8def\u5f84\u5373\u53ef\u8fdb\u884c\u722c\u53d6\u3001\u7ffb\u9875\u7b49\u64cd\u4f5c\uff0c\u7a0b\u5e8f\u4f1a\u7528\u66ff\u6362\u6570\u5b57\u7684\u65b9\u5f0f\u4ea7\u751f\u4efb\u610f\u9875\u7684 url\u3002\r\n\r\n- **\u65e0\u6cd5\u83b7\u53d6\u603b\u9875\u6570\u7684\u9875\u9762**\r\n\r\n\u9488\u5bf9\u8fd9\u79cd\u9875\u9762\u53ef\u6307\u5b9a pages_count \u5c5e\u6027\uff0c\u6216\u5728\u722c\u53d6\u65f6\u8bbe\u7f6e\u722c\u53d6\u9875\u6570\u3002  \r\n\u5982\u4e24\u8005\u90fd\u4e0d\u8bbe\u7f6e\uff0c\u5728\u722c\u5168\u90e8\u9875\u65f6\uff0c\u7a0b\u5e8f\u76f4\u5230\u7a7a\u9875\u6216\u6ca1\u6709\u4e0b\u4e00\u9875\u6309\u94ae\u65f6\u5c31\u4f1a\u505c\u4e0b\u3002\r\n\r\n```python\r\npage.pages_count = 100  # \u624b\u52a8\u8bbe\u7f6e\u603b\u9875\u6570\r\npage.get_list(targets, count=100)  # \u5728\u722c\u53d6\u65f6\u6307\u5b9a\u722c\u53d6\u9875\u6570\r\n```\r\n\r\n- **JS \u52a0\u8f7d\u7684\u5217\u8868\u9875**\r\n\r\n\u8fd9\u79cd\u5217\u8868\u9875\u4f7f\u7528 ajax \u83b7\u53d6\u5217\u8868\u5185\u5bb9\uff0curl \u4e0d\u4f1a\u53d8\u5316\uff0c\u9002\u5408\u7528 d \u6a21\u5f0f\u8fdb\u884c\u722c\u53d6\u3002  \r\nd \u6a21\u5f0f\u4f7f\u7528 selenium \u6a21\u62df\u64cd\u4f5c\u7f51\u9875\uff0c\u53cd\u590d\u70b9\u51fb\u4e0b\u4e00\u9875\u6309\u94ae\u5373\u53ef\u5b9e\u73b0\u7ffb\u9875\u3002\r\n\r\n```python\r\npage = ListPage(xpaths, index_url, 'd')  # \u7528d\u6a21\u5f0f\u521b\u5efa\u5217\u8868\u9875\u5bf9\u8c61\r\n```\r\n\r\n- **\u6a21\u5f0f\u5207\u6362**\r\n\r\nListPage \u7ee7\u627f\u81ea MixPage\uff0c\u56e0\u6b64\u4e5f\u652f\u6301 s \u6a21\u5f0f\u548c d \u6a21\u5f0f\u4e4b\u95f4\u7684\u5207\u6362\uff0c\u4ee5\u53ca MixPage \u4e00\u5207\u529f\u80fd\u3002\r\n\r\n```python\r\npage.change_mod()  # \u5207\u6362\u6a21\u5f0f\r\n```\r\n\r\nMixPage \u8be6\u60c5\u8bf7\u67e5\u770b [DrissionPage \u5e93](https://gitee.com/g1879/DrissionPage)\r\n\r\n## ScrollingPage \u7c7b\r\n\r\nScrollingPage \u7c7b\u662f\u6eda\u52a8\u52a0\u8f7d\u5f0f\u5217\u8868\u9875\u57fa\u672c\u7c7b\uff0c\u7ee7\u627f\u81ea DrissionPage \u7684 MixPage \u7c7b\u3002  \r\n\u4e13\u95e8\u7528\u4e8e\u5904\u7406\u6eda\u52a8\u52a0\u8f7d\u5f0f\u5217\u8868\u9875\u9762\u3002\u5982\u65b0\u95fb\u5217\u8868\u9875\u3002  \r\n\u5c01\u88c5\u4e86\u5bf9\u9875\u9762\u7684\u57fa\u672c\u8bfb\u53d6\u548c\u64cd\u4f5c\u65b9\u6cd5\uff0c\u53ea\u80fd\u5728 MixPage \u7684 d \u6a21\u5f0f\u4e0b\u5de5\u4f5c\u3002  \r\n\r\n**\u521b\u5efa ScrollingPage \u7c7b\u5bf9\u8c61**\r\n\r\n```python\r\npage = ScrollingPage(paths, index_url, timeout, drission)\r\n```\r\n\r\n\u53c2\u6570\u542b\u4e49\u4e0e ListPage \u76f8\u540c\uff0c\u4e0d\u518d\u8d58\u8ff0\u3002\r\n\r\n**ScrollingPage \u5c5e\u6027**\r\n\r\n```python\r\npage.paths  # \u9875\u9762\u5143\u7d20\u7ba1\u7406\u5bf9\u8c61\r\n```\r\n\r\n**ScrollingPage \u65b9\u6cd5**\r\n\r\n```python\r\npage.to_first_page()  # \u91cd\u65b0\u8bbf\u95ee\u9875\u9762\uff0c\u56de\u5230\u9996\u9875\r\npage.get_current_rows()  # \u83b7\u53d6\u5f53\u524d\u884c\u5bf9\u8c61\r\npage.get_current_list(targets, show_msg)  # \u6839\u636eTargets\u5b9a\u4e49\uff0c\u83b7\u53d6\u5f53\u524d\u9875\u9762\u6570\u636e\r\npage.to_next_page(wait)  # \u4e0b\u62c9\uff0c\u52a0\u8f7d\u65b0\u5185\u5bb9\r\npage.get_new_rows()  # \u83b7\u53d6\u65b0\u52a0\u8f7d\u7684\u884c\u5bf9\u8c61\r\npage.get_new_list(targets, show_msg)  # \u6839\u636eTargets\u5b9a\u4e49\uff0c\u83b7\u53d6\u65b0\u52a0\u8f7d\u7684\u6570\u636e\r\npage.click_more_btn(wait)  # \u70b9\u51fb\u52a0\u8f7d\u66f4\u591a\u6309\u94ae\uff08\u5982\u6709\u5b9a\u4e49\uff09\r\npage.get_list(targets, scroll_times, wait, show_msg, recorder, return_data)\r\n'''\u53c2\u6570\u8bf4\u660e\r\ntargets: Targets\u5bf9\u8c61\u6216\u76ee\u6807\u5b57\u5178\r\nscroll_times: \u6eda\u52a8\u6b21\u6570\r\nwait: \u6eda\u52a8\u540e\u7b49\u5f85\u79d2\u6570\r\nshow_msg: \u662f\u5426\u5b9e\u65f6\u6253\u5370\u722c\u53d6\u5230\u7684\u4fe1\u606f\r\nrecorder: \u8bb0\u5f55\u5668\u5bf9\u8c61\uff0c\u8be6\u89c1\u4e0b\u6587\r\nreturn_data: \u662f\u5426\u8fd4\u56de\u7ed3\u679c\uff0c\u5982\u8bbe\u7f6e\u4e86\u8bb0\u5f55\u5668\uff0c\u4e0d\u8fd4\u56de\u7ed3\u679c\u53ef\u4ee5\u8282\u7701\u5185\u5b58\r\n'''\r\n```\r\n\r\n\u56e0\u4e3a\u65e0\u6cd5\u5f97\u77e5\u6eda\u52a8\u9875\u9762\u7684\u957f\u5ea6\uff0c\u6240\u4ee5\u6eda\u52a8\u9875\u9762\u722c\u53d6\u5185\u5bb9\u65f6\u5fc5\u987b\u6307\u5b9a\u6eda\u52a8\u6b21\u6570\u3002\r\n\r\n\u5176\u4f59\u7528\u6cd5\u4e0e ListPage \u7c7b\u4f3c\u3002\r\n\r\n## Recorder \u6a21\u5757\r\n\r\nRecorder \u5bf9\u8c61\u7528\u4e8e\u6682\u7f13\u5199\u5165\u6570\u636e\uff0c\u5b83\u53ef\u63a5\u6536\u5217\u8868\u6570\u636e\uff0c\u8fbe\u5230\u4e00\u5b9a\u6570\u91cf\u65f6\u624d\u4e00\u6b21\u8fdb\u884c\u5199\u5165\uff0c\u4ee5\u964d\u4f4e\u6587\u4ef6\u8bfb\u5199\u6b21\u6570\uff0c\u51cf\u5c11\u5f00\u9500\u3002\u53ef\u652f\u6301 .csv\u3001.txt\u3001.xlsx\u3001.json \u56db\u79cd\u683c\u5f0f\u6587\u4ef6\u3002\r\n\r\n\u8be6\u7ec6\u5185\u5bb9\u8bf7\u89c1\uff1a[DataRecorder: \u7528\u4e8e\u8bb0\u5f55\u6570\u636e\u7684\u6a21\u5757\u3002 (gitee.com)](https://gitee.com/g1879/DataRecorder)\r\n\r\n**\u521b\u5efa Recorder \u5bf9\u8c61**\r\n\r\n```python\r\nrecorder = Recorder(file_path, cache_size)\r\n```\r\n\r\n**Recorder \u5c5e\u6027**\r\n\r\n```python\r\nrecorder.cache_size  # \u7f13\u5b58\u5927\u5c0f\r\nrecorder.file_path  # \u6587\u4ef6\u8def\u5f84\r\nrecorder.encoding  # \u7f16\u7801\u683c\u5f0f\r\n```\r\n\r\n**Recorder \u65b9\u6cd5**\r\n\r\n```python\r\nrecorder.add_data(data)  # \u6dfb\u52a0\u4e00\u6279\u6570\u636e\uff0c\u5217\u8868\u6216\u5143\u7ec4\u683c\u5f0f\r\nrecorder.record()  # \u5c06\u7f13\u5b58\u8bb0\u5f55\u5230\u6587\u4ef6\u7136\u540e\u6e05\u7a7a\r\nrecorder.set_head(head)  # \u8bbe\u7f6e\u8868\u5934\uff0ccsv\u548cxlsx\u683c\u5f0f\u9002\u7528\r\nrecorder.set_before(before_col)  # \u8bbe\u7f6e\u6570\u636e\u524d\u7684\u5217\uff0c\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u683c\u5f0f\r\nrecorder.set_after(after_col)  # \u8bbe\u7f6e\u6570\u636e\u540e\u7684\u5217\uff0c\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u683c\u5f0f\r\nrecorder.clear()  # \u6e05\u7a7a\u7f13\u5b58\r\n```\r\n\r\n**Tips:** \r\n\r\n- set_before() \u548c set_after() \u7528\u4e8e\u6dfb\u52a0\u4e0d\u662f\u5728\u9875\u9762\u4e2d\u83b7\u53d6\u5230\u7684\u6570\u636e\uff0c\u901a\u5e38\u7528\u4e8e\u533a\u5206\u591a\u6279\u5199\u5165\u6570\u636e\uff0c\u5982\u591a\u6b21\u722c\u53d6\u7684\u6807\u8bc6\u7b49\u3002\u793a\u4f8b\uff1a\u722c\u4e8c\u624b\u623f\u65f6\u5404\u533a\u6570\u636e\u90fd\u8bb0\u5f55\u5728\u4e00\u4e2a\u8868\uff0c\u5c31\u8981\u5728\u722c\u53d6\u5230\u7684\u6570\u636e\u524d\u52a0\u4e00\u4e2a\u533a\u5217\u3002\u8be6\u89c1\u4e0b\u6587\u793a\u4f8b\u3002\r\n- csv \u548c xlsx \u5199\u5165\u65f6\u4f1a\u6309\u7167\u7ed3\u679c\u5b57\u5178\u521b\u5efa\u8868\u5934\uff0c\u5982set_before() \u548c set_after() \u53c2\u6570\u4e5f\u662f\u5b57\u5178\uff0c\u4e5f\u53ef\u81ea\u52a8\u5199\u5165\u8868\u5934\uff0c\u4e00\u822c\u65e0\u987b set_head()\u3002\r\n- \u9664\u4e86 xlsx \u7c7b\u578b\uff0c\u5176\u4f593\u79cd\u7c7b\u578b\u5728\u7a0b\u5e8f\u7ed3\u675f\u65f6\u53ef\u81ea\u52a8\u8bb0\u5f55\u672a\u4fdd\u5b58\u6570\u636e\uff0c\u5305\u62ec\u56e0\u5f02\u5e38\u7ed3\u675f\u65f6\u3002xlsx \u987b\u7ed3\u675f\u524d\u624b\u52a8\u8c03\u7528 record()\u3002\r\n\r\n---\r\n\r\n# APIs\r\n\r\n***\r\n\r\n\u8bf7\u5728 wiki \u4e2d\u67e5\u770b\uff1a[APIs](https://gitee.com/Drission/ListPage/wikis/Home)\r\n",
    "bugtrack_url": null,
    "license": "BSD",
    "summary": "Page classes dedicated to crawling or manipulating list web pages.",
    "version": "1.0.5",
    "project_urls": {
        "Homepage": "https://gitee.com/Drission/ListPage"
    },
    "split_keywords": [
        "page",
        "classes"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "619d127ff9cc35e5c3ada65612c029aa469a085dc44d6c3a4537db405fc9a322",
                "md5": "67faa7e22a0dda0f52b2d5a8b254a1d5",
                "sha256": "62deb6416c80a58140f1e5464486958933f4664281bf9d33bd8fc92af1a79ec2"
            },
            "downloads": -1,
            "filename": "ListPage-1.0.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "67faa7e22a0dda0f52b2d5a8b254a1d5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 21353,
            "upload_time": "2024-03-12T14:37:38",
            "upload_time_iso_8601": "2024-03-12T14:37:38.299879Z",
            "url": "https://files.pythonhosted.org/packages/61/9d/127ff9cc35e5c3ada65612c029aa469a085dc44d6c3a4537db405fc9a322/ListPage-1.0.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "eaa89698499cb049e459c399b6f9a303eb6c45cc86b67cadc3f64f85cc343f79",
                "md5": "75523cc7db3e571caae4b89aada6901c",
                "sha256": "99d1c556c1433e084fa3f6a03142c34d511ed9f3f78f465e0f12d3ffe97107a1"
            },
            "downloads": -1,
            "filename": "ListPage-1.0.5.tar.gz",
            "has_sig": false,
            "md5_digest": "75523cc7db3e571caae4b89aada6901c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 17373,
            "upload_time": "2024-03-12T14:37:40",
            "upload_time_iso_8601": "2024-03-12T14:37:40.243751Z",
            "url": "https://files.pythonhosted.org/packages/ea/a8/9698499cb049e459c399b6f9a303eb6c45cc86b67cadc3f64f85cc343f79/ListPage-1.0.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-12 14:37:40",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "listpage"
}
        
Elapsed time: 0.21044s