scrapy-drissionpage 1.0.3
将Scrapy爬虫框架与DrissionPage网页自动化工具进行无缝集成
License: MIT
Requires Python: >=3.9
Keywords: scrapy, drissionpage, crawler, spider, web scraping, automation, commercial-use, personal-use

# Scrapy DrissionPage 集成工具

## 📌 项目简介

Scrapy DrissionPage 是一个将 DrissionPage 与 Scrapy 框架无缝集成的扩展工具，让您可以在 Scrapy 爬虫中使用 DrissionPage 的全部功能。本扩展工具支持浏览器自动化和数据包收发两种模式，并可以自由切换，大幅提高爬虫开发效率与稳定性。

### 主要特性：

- 🌐 **模式自由切换**：支持在浏览器模式（chromium）和会话模式（session）间动态切换
- 🚀 **性能优化**：提供数据读取加速功能，支持静态解析，提高数据提取速度
- 📦 **数据包监听**：可监听网络请求，轻松获取AJAX加载的数据
- 📥 **文件下载**：集成下载功能，支持自定义保存路径和文件名
- 🔍 **简洁语法**：兼容DrissionPage的简洁元素定位语法，大大减少代码量

## 📥 安装方法

### 依赖项

- Python 3.9+
- Scrapy 2.12.0+
- DrissionPage 4.1.0.18+

### 安装命令

```bash
# 安装DrissionPage
pip install DrissionPage>=4.1.0.18

# 安装扩展工具
pip install scrapy-drissionpage
```

## ⚙️ 基本配置

在 Scrapy 项目的 `settings.py` 中添加以下配置：

```python
# 启用中间件
DOWNLOADER_MIDDLEWARES = {
    'scrapy_drissionpage.middleware.DrissionPageMiddleware': 543,
}

# DrissionPage配置
DRISSIONPAGE_HEADLESS = True  # 是否无头模式
DRISSIONPAGE_LOAD_MODE = 'normal'  # 页面加载模式：normal, eager, none
DRISSIONPAGE_DOWNLOAD_PATH = 'downloads'  # 下载路径
DRISSIONPAGE_TIMEOUT = 30  # 请求超时时间
DRISSIONPAGE_RETRY_TIMES = 3  # 重试次数
DRISSIONPAGE_RETRY_INTERVAL = 2  # 重试间隔（秒）

# 浏览器设置
DRISSIONPAGE_BROWSER_PATH = None  # 浏览器路径，None使用默认浏览器
DRISSIONPAGE_INCOGNITO = True  # 是否使用无痕模式
DRISSIONPAGE_CHROME_OPTIONS = ['--disable-gpu']  # Chrome启动选项
```

## 🧰 使用方法

### 1. 创建爬虫

继承 `DrissionSpider` 类创建爬虫：

```python
from scrapy_drissionpage.spider import DrissionSpider

class MySpider(DrissionSpider):
    name = 'myspider'
    
    def start_requests(self):
        # 创建浏览器模式请求
        yield self.drission_request(
            'https://example.com',
            page_type='chromium',  # 使用浏览器模式
            callback=self.parse
        )
        
        # 创建会话模式请求
        yield self.drission_request(
            'https://example.com/api',
            page_type='session',  # 使用会话模式
            callback=self.parse_api
        )
    
    def parse(self, response):
        # 使用DrissionPage的语法查找元素
        title = response.ele('tag:h1').text
        yield {'title': title}
```

### 2. 模式切换

您可以在不同的请求间动态切换模式，DrissionPage 4.1.0.18版本已支持更便捷的模式切换：

```python
def parse_login(self, response):
    # 先使用浏览器模式登录
    response.page.ele('#username').input('user123')
    response.page.ele('#password').input('password123')
    response.page.ele('#login-btn').click()
    
    # 获取当前会话的session对象并使用它发送请求
    session_page = self.get_utils().ModeSwitcher.to_session(response.page)
    
    # 或者直接使用DrissionRequest发送会话模式请求
    yield self.drission_request(
        'https://example.com/api/data',
        page_type='session',  # 切换到会话模式
        callback=self.parse_data
    )
```

### 3. 数据提取加速

使用 `s_ele` 和 `s_eles` 方法进行静态解析，提高数据提取速度：

```python
def parse(self, response):
    # 常规方式
    # links = response.eles('t:a')  # 速度较慢
    
    # 加速方式
    links = response.s_eles('t:a')  # 速度提升约10倍
    
    for link in links:
        yield {
            'text': link.text,
            'url': link.attr('href')
        }
```

### 4. 数据包监听

监听和拦截页面上的网络请求：

```python
def parse_with_monitor(self, response):
    # 开始监听API请求
    response.page.listen.xhr(callback=self.handle_xhr)
    
    # 点击按钮触发AJAX请求
    response.page.ele('#load-more').click()
    
    # 等待一段时间让请求完成
    response.wait(3)
    
    # 获取完数据后停止加载（适用于none加载模式）
    response.page.stop_loading()

def handle_xhr(self, flow):
    # 处理XHR请求
    if 'api/data' in flow.request.url:
        data = flow.response.json
        # 处理数据...
```

### 5. 文件下载

使用内置的下载功能：

```python
def parse_download(self, response):
    # 设置下载配置
    response.page.download.set_path('files')
    
    # 点击下载按钮并指定文件名
    response.page.ele('#download-btn').click()
    
    # 等待下载完成
    mission = response.page.wait.download_begin()
    mission.wait()
    
    yield {'file_path': mission.path}
```

## 📚 高级功能

### 1. 多标签页操作

```python
def parse_multi_tabs(self, response):
    # 创建新标签页
    tab2 = response.page.new_tab('https://example.com/page2')
    
    # 从第一个标签页获取数据
    title1 = response.page.title
    
    # 从第二个标签页获取数据
    title2 = tab2.title
    
    # 切换回原标签页
    response.page.activate_tab()
    
    yield {
        'title1': title1,
        'title2': title2
    }
```

### 2. iframe 操作

```python
def parse_iframe(self, response):
    # 获取iframe对象
    iframe = response.page.get_frame('#my-iframe')
    
    # 在iframe中查找元素
    data = iframe.ele('#data').text
    
    yield {'iframe_data': data}
```

### 3. 执行JavaScript

```python
def parse_with_js(self, response):
    # 执行JavaScript代码
    result = response.page.run_js('return document.title')
    
    # 修改页面元素
    response.page.run_js('document.getElementById("demo").innerHTML = "Hello JavaScript"')
    
    yield {'js_result': result}
```

## 🌰 完整示例

### 例1：爬取GiteeExplore页面项目列表

```python
import scrapy
from scrapy_drissionpage.spider import DrissionSpider

class GiteeSpider(DrissionSpider):
    name = 'gitee_spider'
    
    def start_requests(self):
        yield self.drission_request(
            'https://gitee.com/explore',
            page_type='session',  # 使用会话模式即可，不需要JavaScript
            callback=self.parse
        )
    
    def parse(self, response):
        # 使用静态解析加速
        ul_ele = response.s_ele('tag:ul@text():全部推荐项目')
        projects = ul_ele.s_eles('tag:a')
        
        for project in projects:
            # 只处理有href属性的链接
            if project.attr('href') and '/explore/' not in project.attr('href'):
                yield {
                    'name': project.text,
                    'url': response.urljoin(project.attr('href'))
                }
```

### 例2：处理需要登录的网站

```python
import scrapy
from scrapy_drissionpage.spider import DrissionSpider

class LoginSpider(DrissionSpider):
    name = 'login_spider'
    
    def start_requests(self):
        yield self.drission_request(
            'https://example.com/login',
            page_type='chromium',  # 使用浏览器模式处理登录
            callback=self.login
        )
    
    def login(self, response):
        # 填写登录表单
        response.page.ele('#username').input('your_username')
        response.page.ele('#password').input('your_password')
        response.page.ele('#login-btn').click()
        
        # 等待登录成功，页面跳转
        response.page.wait.url_change()
        
        # 登录成功后访问用户中心
        yield self.drission_request(
            'https://example.com/user/dashboard',
            page_type='session',  # 登录后切换到会话模式提高效率
            callback=self.parse_dashboard
        )
    
    def parse_dashboard(self, response):
        # 提取用户信息
        username = response.ele('.user-name').text
        points = response.ele('.user-points').text
        
        yield {
            'username': username,
            'points': points
        }
```

## 📋 版本说明

### v1.0.2 (最新版)
- 🚀 支持DrissionPage 4.1.0.18版本
- 🛠 更新了API使用方式，适配最新的DrissionPage接口
- 🔄 提供向后兼容性支持，确保与旧版本兼容
- 🐛 修复了cookies设置问题

### v1.0.1
- 🐛 修复了包发布配置问题
- 🔧 优化了依赖管理

### v1.0.0
- 🎉 首次发布
- 🔌 提供了Scrapy与DrissionPage的基本集成功能

## 📄 许可证

本项目采用 MIT 许可证，允许个人和商业使用。

- **个人使用**：任何个人可以自由使用、修改和分发本软件。
- **商业用途**：允许将本软件用于商业产品和服务，无需支付额外费用。

查看完整的 [LICENSE](LICENSE) 文件获取更多信息。

---

通过以上配置和示例，您可以开始使用Scrapy DrissionPage扩展工具进行高效的网页抓取。该工具结合了Scrapy的分布式抓取能力和DrissionPage的强大自动化功能，为您提供了一个强大而灵活的网络抓取解决方案。