Skip to main content

一个基于 Playwright 和 LLM 的智能爬虫工具

Project description

Xpidy - 智能网页数据提取框架

一个基于Playwright的现代化智能爬虫库,采用"配置驱动"设计理念,让网页数据提取变得极其简单。

✨ 特性

  • 🎯 配置驱动 - 基于配置的自动化数据提取,配置即文档
  • 🚀 极简API - 配置完成后只需 await spider.crawl(url)
  • 🎭 Playwright驱动 - 支持JavaScript渲染和SPA应用
  • 高性能 - 多提取器并发执行,内置智能缓存
  • 🧠 LLM增强 - 可选的大语言模型后处理优化
  • 📋 全面提取 - 文本、链接、图片、表格、表单等多种数据
  • 🔍 灵活选择器 - 支持CSS选择器和XPath范围限制
  • 🛡️ 反爬虫 - 内置隐身模式和随机延迟
  • 🔧 CLI工具 - 完整的命令行工具支持

🚀 快速开始

安装

# 安装uv(如果尚未安装)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 克隆项目
git clone https://github.com/Ciciy-l/Xpidy.git
cd Xpidy

# 安装依赖
uv sync

# 安装Playwright浏览器
uv run playwright install

最简使用方式

import asyncio
from xpidy import Spider

async def main():
    # 快速创建爬虫实例
    spider = Spider.quick_create(
        enable_text=True,      # 提取文本
        enable_links=True,     # 提取链接
        enable_images=True     # 提取图片
    )
    
    # 一行代码完成所有提取
    async with spider:
        result = await spider.crawl("https://example.com")
        print(f"提取完成!文本: {len(result['results']['text']['content'])}字符")

asyncio.run(main())

配置驱动方式

import asyncio
from xpidy import Spider, XpidyConfig, ExtractionConfig, SpiderConfig

async def main():
    # 1. 定义配置(配置即文档)
    config = XpidyConfig(
        spider_config=SpiderConfig(
            headless=True,
            timeout=30000,
            stealth_mode=True
        ),
        extraction_config=ExtractionConfig(
            enable_text=True,
            enable_links=True, 
            enable_images=True,
            text_config={"min_text_length": 10},
            links_config={"max_items": 50},
            images_config={"max_items": 20}
        )
    )
    
    # 2. 创建爬虫实例
    async with Spider(config) as spider:
        # 3. 一键提取所有配置的数据
        result = await spider.crawl("https://example.com")
        
        # 4. 使用结构化结果
        print(f"URL: {result['url']}")
        print(f"提取器: {result['extractors_used']}")
        print(f"耗时: {result['extraction_time']:.2f}秒")
        
        # 5. 访问各提取器结果
        if 'text' in result['results']:
            text_data = result['results']['text']
            print(f"文本长度: {len(text_data['content'])}字符")
            print(f"标题: {text_data['metadata']['title']}")
        
        if 'links' in result['results']:
            links_data = result['results']['links']
            print(f"链接数量: {links_data['total_links']}")
            print(f"内部链接: {len(links_data['internal_links'])}")
        
        if 'images' in result['results']:
            images_data = result['results']['images']
            print(f"图片数量: {images_data['total_images']}")

asyncio.run(main())

📋 CLI使用指南

基础命令

# 1. 生成配置模板
xpidy init basic --output my_config.json

# 2. 验证配置文件
xpidy validate my_config.json

# 3. 执行爬取任务
xpidy run my_config.json --output results.json

# 4. 快速爬取单个URL
xpidy quick https://example.com --enable-links --enable-images

配置文件示例

{
  "spider_config": {
    "headless": true,
    "timeout": 30000,
    "stealth_mode": true
  },
  "extraction_config": {
    "enable_text": true,
    "enable_links": true,
    "enable_images": true,
    "text_config": {
      "min_text_length": 10,
      "extract_metadata": true
    },
    "links_config": {
      "include_internal": true,
      "include_external": true,
      "max_items": 50
    },
    "images_config": {
      "min_width": 100,
      "min_height": 100,
      "max_items": 20
    }
  },
  "tasks": [
    {
      "url": "https://example.com",
      "name": "example_site"
    }
  ]
}

可用模板

# 基础文本提取
xpidy init basic

# 链接分析  
xpidy init links

# 图片分析
xpidy init images

# 全面数据提取
xpidy init comprehensive

# 结构化数据提取
xpidy init data

# 表单数据提取
xpidy init form

🔧 高级功能

1. 选择器范围限制

from xpidy import XpidyConfig, ExtractionConfig, SpiderConfig

config = XpidyConfig(
    extraction_config=ExtractionConfig(
        enable_text=True,
        enable_links=True,
        # 全局选择器限制
        css_selector="main .content",  # 只在主内容区域提取
        text_config={
            "css_selector": "article p"  # 文本提取器专用选择器
        },
        links_config={
            "css_selector": "nav a, .sidebar a"  # 链接提取器专用选择器
        }
    )
)

2. 配置文件保存与加载

# 保存配置
config = XpidyConfig(...)
config.save_to_file("my_config.json")

# 从文件加载配置
config = XpidyConfig.from_file("my_config.json")

3. LLM后处理(可选)

from xpidy import LLMConfig

config = XpidyConfig(
    extraction_config=ExtractionConfig(enable_text=True),
    llm_config=LLMConfig(
        provider="openai",
        model="gpt-3.5-turbo", 
        api_key="your-api-key",
        enabled=True
    )
)

async with Spider(config) as spider:
    # 使用LLM优化结果
    result = await spider.crawl(
        "https://example.com",
        prompt="请提取关键信息并整理为结构化格式"
    )

4. 并发批量处理

urls = [
    "https://example1.com",
    "https://example2.com", 
    "https://example3.com"
]

async with Spider(config) as spider:
    # 并发处理多个URL
    results = []
    tasks = [spider.crawl(url) for url in urls]
    results = await asyncio.gather(*tasks, return_exceptions=True)

🏗️ 架构设计

核心设计理念

  1. 配置驱动:所有提取逻辑通过配置声明,运行时自动执行
  2. 并发架构:多提取器自动并发执行,提高效率
  3. 智能缓存:提取器内部结果暂存,避免重复计算
  4. 优雅错误处理:单点失败不影响整体,详细错误日志

架构层次

用户层: 极简API (Spider.crawl)
配置层: 声明式配置 (XpidyConfig, ExtractionConfig, SpiderConfig)
控制层: 智能调度 (Spider内部并发管理)
执行层: 专用提取器 (TextExtractor, LinkExtractor, ImageExtractor等)
基础层: 统一抽象 (BaseExtractor, Playwright)

📁 项目结构

Xpidy/
├── xpidy/                      # 主包
│   ├── core/                   # 核心模块
│   │   ├── spider.py           # 主爬虫类
│   │   ├── config.py           # 配置类定义  
│   │   ├── llm_processor.py    # LLM处理器
│   │   └── __init__.py         # 核心模块导出
│   ├── extractors/             # 数据提取器模块
│   │   ├── base_extractor.py   # 提取器基类
│   │   ├── text_extractor.py   # 文本提取器
│   │   ├── link_extractor.py   # 链接提取器
│   │   ├── image_extractor.py  # 图片提取器
│   │   ├── data_extractor.py   # 结构化数据提取器
│   │   ├── form_extractor.py   # 表单提取器
│   │   └── __init__.py         # 提取器模块导出
│   ├── utils/                  # 工具模块
│   │   ├── cache.py            # 缓存管理
│   │   ├── content_utils.py    # 内容处理工具
│   │   ├── url_utils.py        # URL处理工具
│   │   └── __init__.py         # 工具模块导出
│   ├── cli.py                  # 配置驱动的命令行工具
│   └── __init__.py             # 包主入口
├── examples/                   # 示例代码
├── tests/                      # 测试文件
├── .venv/                      # 虚拟环境 (uv管理)
├── pyproject.toml              # 项目配置文件
├── uv.lock                     # 依赖锁定文件
└── README.md                   # 项目说明文档

🔧 配置详解

SpiderConfig(爬虫配置)

from xpidy import SpiderConfig

spider_config = SpiderConfig(
    browser_type="chromium",      # 浏览器类型: chromium/firefox/webkit
    headless=True,                # 无头模式
    timeout=30000,                # 超时时间(毫秒)
    stealth_mode=True,            # 隐身模式
    random_delay=True,            # 随机延迟
    min_delay=0.5,                # 最小延迟(秒)
    max_delay=2.0,                # 最大延迟(秒)
    max_retries=3,                # 最大重试次数
    user_agent="custom-ua",       # 自定义UA
    viewport_width=1920,          # 视口宽度
    viewport_height=1080          # 视口高度
)

ExtractionConfig(提取配置)

from xpidy import ExtractionConfig

extraction_config = ExtractionConfig(
    # 启用的提取器
    enable_text=True,
    enable_links=True,
    enable_images=True,
    enable_data=True,
    enable_form=True,
    
    # 全局选择器(影响所有提取器)
    css_selector="main",          # CSS选择器范围限制
    xpath_selector="//main",      # XPath选择器范围限制
    
    # 各提取器专用配置
    text_config={
        "min_text_length": 10,
        "extract_metadata": True,
        "clean_content": True
    },
    links_config={
        "include_internal": True,
        "include_external": True,
        "max_items": 100,
        "filter_patterns": ["*.pdf", "*.zip"]
    },
    images_config={
        "min_width": 50,
        "min_height": 50,
        "max_items": 50,
        "allowed_formats": ["jpg", "png", "gif", "webp"]
    },
    data_config={
        "extract_json_ld": True,
        "extract_microdata": True,
        "extract_tables": True
    },
    form_config={
        "extract_input_fields": True,
        "extract_buttons": True,
        "include_hidden_fields": False
    }
)

LLMConfig(LLM配置)

from xpidy import LLMConfig

llm_config = LLMConfig(
    enabled=True,                 # 启用LLM处理
    provider="openai",            # 提供商: openai/anthropic
    model="gpt-3.5-turbo",        # 模型名称
    api_key="your-api-key",       # API密钥
    temperature=0.1,              # 温度参数
    max_tokens=2000               # 最大令牌数
)

🧪 开发环境

# 激活虚拟环境
source .venv/bin/activate  # Linux/Mac
# 或
.venv\Scripts\activate     # Windows

# 运行测试
uv run pytest

# 运行示例测试
uv run python test_refactored.py

# 测试CLI工具
uv run xpidy init basic --output test_config.json
uv run xpidy validate test_config.json
uv run xpidy run test_config.json

# 代码格式化
uvx isort .
uvx black .

📊 性能特性

并发提取

所有提取器在爬取过程中并发执行:

# 内部实现伪代码
async def crawl(self, url):
    # 创建并发任务
    tasks = []
    if self.config.extraction_config.enable_text:
        tasks.append(self._extractors['text'].extract(page))
    if self.config.extraction_config.enable_links:
        tasks.append(self._extractors['links'].extract(page))
    if self.config.extraction_config.enable_images:
        tasks.append(self._extractors['images'].extract(page))
    
    # 并发执行所有提取器
    results = await asyncio.gather(*tasks, return_exceptions=True)

智能缓存

每个提取器内部维护结果缓存,避免重复计算:

# 自动缓存机制
class TextExtractor(BaseExtractor):
    async def extract(self, page):
        if self._cached_result:
            return self._cached_result
        
        result = await self._do_extract(page)
        self._cached_result = result  # 自动缓存
        return result

错误隔离

单个提取器失败不影响其他提取器:

# 优雅错误处理
results = await asyncio.gather(*tasks, return_exceptions=True)
for extractor_name, result in zip(enabled_extractors, results):
    if isinstance(result, Exception):
        logger.warning(f"提取器 {extractor_name} 失败: {result}")
        # 继续处理其他提取器结果

📄 许可证

MIT License

🤝 贡献

欢迎提交Issue和Pull Request!


Xpidy - 让网页数据提取变得简单而强大! 🕷️✨

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xpidy-0.2.0.tar.gz (107.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xpidy-0.2.0-py3-none-any.whl (64.0 kB view details)

Uploaded Python 3

File details

Details for the file xpidy-0.2.0.tar.gz.

File metadata

  • Download URL: xpidy-0.2.0.tar.gz
  • Upload date:
  • Size: 107.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.3

File hashes

Hashes for xpidy-0.2.0.tar.gz
Algorithm Hash digest
SHA256 2486f15c462444fc64659d4e8e6fb50ede0ff563af339ea005ad874e08604d83
MD5 954577a43a69d5b4c049027d307fd1a0
BLAKE2b-256 2ee6c2afa511217c11683b50739a0f816ce5270723584ed1421e5884f5fdd26e

See more details on using hashes here.

File details

Details for the file xpidy-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: xpidy-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 64.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.3

File hashes

Hashes for xpidy-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c19bc864f49405656a17e8327b6c0d1bc56e9800c6c367ad563117495562234
MD5 d864e0fb5f579c0f2569072b4de6fb44
BLAKE2b-256 d101fb49258a0478c310b1c8e31bcaaf7477ae9f0deaa8ebbaa8f3ab086818d4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page