返回顶部
7*24新情报

【教程】用Python+Playwright打造AI智能网页爬虫,自动提取结构化数据

[复制链接]
嗜血的兔子 显示全部楼层 发表于 昨天 06:26 |阅读模式 打印 上一主题 下一主题
【教程】用Python+Playwright打造AI智能网页爬虫,自动提取结构化数据
本教程基于GitHub热门项目AgentQL和Skyvern的思路,教你用Python+Playwright构建一个能自动理解网页结构、智能提取数据的爬虫工具。无需写繁琐的XPath,AI帮你定位元素!

一、前置条件

在开始之前,请确保你已安装以下环境:


  • Python 3.9+
  • pip 包管理器
  • 一个可用的LLM API Key(OpenAI、Claude、Kimi等均可)


二、核心原理

传统爬虫需要人工分析HTML结构、编写XPath或CSS选择器。而AI智能爬虫的工作流程是:
  1. 1. Playwright 加载目标网页并截图
  2. 2. 将页面HTML + 截图发送给LLM
  3. 3. LLM分析页面结构,返回数据提取策略
  4. 4. 按策略提取数据,输出结构化结果
复制代码

这种方法的优势:

  • 自适应页面结构变化,无需维护选择器
  • 能理解复杂布局(表格、卡片、瀑布流)
  • 支持多页自动翻页、表单填写


三、步骤详解

步骤1:安装依赖
  1. pip install playwright openai python-dotenv
  2. playwright install chromium
复制代码

步骤2:创建配置文件 .env
  1. OPENAI_API_KEY=your_api_key_here
  2. OPENAI_BASE_URL=https://api.openai.com/v1  # 或其他兼容接口
复制代码

步骤3:编写智能爬虫核心代码

创建 ai_scraper.py
  1. import os
  2. import json
  3. import base64
  4. from playwright.sync_api import sync_playwright
  5. from openai import OpenAI
  6. from dotenv import load_dotenv
  7. load_dotenv()
  8. class AIScraper:
  9.     def __init__(self):
  10.         self.client = OpenAI(
  11.             api_key=os.getenv("OPENAI_API_KEY"),
  12.             base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
  13.         )
  14.    
  15.     def capture_page(self, url):
  16.         """用Playwright加载页面并截图"""
  17.         with sync_playwright() as p:
  18.             browser = p.chromium.launch(headless=True)
  19.             page = browser.new_page(viewport={"width": 1920, "height": 1080})
  20.             page.goto(url, wait_until="networkidle")
  21.             
  22.             # 获取页面HTML
  23.             html = page.content()
  24.             
  25.             # 截图并转为base64
  26.             screenshot = page.screenshot(type="jpeg", quality=80)
  27.             screenshot_b64 = base64.b64encode(screenshot).decode()
  28.             
  29.             browser.close()
  30.             return html, screenshot_b64
  31.    
  32.     def analyze_page(self, html, screenshot_b64, instruction):
  33.         """调用LLM分析页面,返回提取策略"""
  34.         prompt = f"""
  35. 你是一个网页数据提取专家。请分析以下网页内容,帮我提取指定数据。
  36. 提取需求:{instruction}
  37. 页面HTML片段(前5000字符):
  38. {html[:5000]}
  39. 请返回JSON格式的提取策略,包含:
  40. 1. "data_type": 数据类型(list/table/detail)
  41. 2. "selectors": 具体的CSS选择器或提取逻辑
  42. 3. "fields": 需要提取的字段列表
  43. 4. "next_page": 是否有下一页,如何翻页(可选)
  44. 只返回JSON,不要其他解释。
  45. """
  46.         
  47.         response = self.client.chat.completions.create(
  48.             model="gpt-4o-mini",  # 或其他可用模型
  49.             messages=[
  50.                 {
  51.                     "role": "user",
  52.                     "content": [
  53.                         {"type": "text", "text": prompt},
  54.                         {
  55.                             "type": "image_url",
  56.                             "image_url": {
  57.                                 "url": f"data:image/jpeg;base64,{screenshot_b64}"
  58.                             }
  59.                         }
  60.                     ]
  61.                 }
  62.             ],
  63.             response_format={"type": "json_object"}
  64.         )
  65.         
  66.         return json.loads(response.choices[0].message.content)
  67.    
  68.     def extract_data(self, url, instruction):
  69.         """主流程:截图 -> AI分析 -> 提取数据"""
  70.         print(f"正在加载页面:{url}")
  71.         html, screenshot = self.capture_page(url)
  72.         
  73.         print("正在分析页面结构...")
  74.         strategy = self.analyze_page(html, screenshot, instruction)
  75.         
  76.         print(f"提取策略:{json.dumps(strategy, ensure_ascii=False, indent=2)}")
  77.         
  78.         # 根据策略提取数据
  79.         with sync_playwright() as p:
  80.             browser = p.chromium.launch(headless=True)
  81.             page = browser.new_page()
  82.             page.goto(url, wait_until="networkidle")
  83.             
  84.             data = self._execute_strategy(page, strategy)
  85.             browser.close()
  86.             return data
  87.    
  88.     def _execute_strategy(self, page, strategy):
  89.         """根据AI返回的策略执行数据提取"""
  90.         data_type = strategy.get("data_type", "list")
  91.         selectors = strategy.get("selectors", {})
  92.         fields = strategy.get("fields", [])
  93.         
  94.         results = []
  95.         
  96.         if data_type == "list":
  97.             items = page.query_selector_all(selectors.get("item", "body"))
  98.             for item in items[:20]:  # 限制数量
  99.                 row = {}
  100.                 for field in fields:
  101.                     name = field["name"]
  102.                     selector = field.get("selector", "")
  103.                     attr = field.get("attribute", "textContent")
  104.                     
  105.                     el = item.query_selector(selector) if selector else item
  106.                     if el:
  107.                         if attr == "textContent":
  108.                             row[name] = el.text_content().strip()
  109.                         elif attr == "href":
  110.                             row[name] = el.get_attribute("href")
  111.                         else:
  112.                             row[name] = el.get_attribute(attr)
  113.                     else:
  114.                         row[name] = None
  115.                 results.append(row)
  116.         
  117.         elif data_type == "table":
  118.             rows = page.query_selector_all(selectors.get("row", "tr"))
  119.             for row_el in rows[1:]:  # 跳过表头
  120.                 cells = row_el.query_selector_all("td")
  121.                 row = {}
  122.                 for i, field in enumerate(fields):
  123.                     if i < len(cells):
  124.                         row[field["name"]] = cells[i].text_content().strip()
  125.                 results.append(row)
  126.         
  127.         return results
  128. # 使用示例
  129. if __name__ == "__main__":
  130.     scraper = AIScraper()
  131.    
  132.     # 示例:提取新闻列表
  133.     url = "https://news.ycombinator.com"
  134.     instruction = "提取首页所有新闻的标题、链接和评分"
  135.    
  136.     data = scraper.extract_data(url, instruction)
  137.     print(json.dumps(data, ensure_ascii=False, indent=2))
复制代码

步骤4:运行测试
  1. python ai_scraper.py
复制代码

四、进阶:自动翻页采集

如果需要采集多页数据,可以扩展翻页逻辑:
  1. def extract_with_pagination(self, start_url, instruction, max_pages=5):
  2.     """支持自动翻页的数据采集"""
  3.     all_data = []
  4.     current_url = start_url
  5.     page_count = 0
  6.    
  7.     while current_url and page_count < max_pages:
  8.         print(f"正在采集第 {page_count + 1} 页...")
  9.         
  10.         html, screenshot = self.capture_page(current_url)
  11.         strategy = self.analyze_page(html, screenshot, instruction)
  12.         
  13.         with sync_playwright() as p:
  14.             browser = p.chromium.launch(headless=True)
  15.             page = browser.new_page()
  16.             page.goto(current_url, wait_until="networkidle")
  17.             
  18.             data = self._execute_strategy(page, strategy)
  19.             all_data.extend(data)
  20.             
  21.             # 查找下一页链接
  22.             next_selector = strategy.get("next_page", {}).get("selector")
  23.             if next_selector:
  24.                 next_el = page.query_selector(next_selector)
  25.                 current_url = next_el.get_attribute("href") if next_el else None
  26.                 if current_url and not current_url.startswith("http"):
  27.                     from urllib.parse import urljoin
  28.                     current_url = urljoin(start_url, current_url)
  29.             else:
  30.                 current_url = None
  31.             
  32.             browser.close()
  33.         
  34.         page_count += 1
  35.    
  36.     return all_data
复制代码

五、常见问题

Q1:LLM API费用高吗?
使用gpt-4o-mini或国产大模型(如Kimi、通义千问),每次分析成本约0.01-0.05元。对于小规模采集非常划算。

Q2:遇到反爬怎么办?

  • 使用playwright-stealth插件隐藏自动化特征
  • 设置合理的请求间隔(time.sleep(random.uniform(2, 5)))
  • 使用代理IP轮换


Q3:提取结果不准确?

  • 在prompt中提供更详细的字段说明
  • 增加截图分辨率,让LLM看清页面布局
  • 对复杂页面分块处理


Q4:支持JavaScript渲染的页面吗?
支持!Playwright本身就是完整的浏览器,能执行所有JavaScript。

六、总结

通过本教程,你学会了:

  • 用Playwright加载和截图网页
  • 调用LLM智能分析页面结构
  • 自动生成提取策略并执行
  • 支持翻页的自动化数据采集


这种AI+爬虫的组合,大幅降低了维护成本。当目标网站改版时,只需重新运行分析流程,无需手动更新选择器。
项目灵感来源:GitHub热门项目 AgentQL(1.4k+ Star)和 Skyvern(22k+ Star),两者都是AI驱动的新一代网页自动化工具。

相关资源:

  • AgentQL:https://github.com/tinyfish-io/agentql
  • Skyvern:https://github.com/Skyvern-AI/skyvern
  • Playwright文档:https://playwright.dev/python/


有问题欢迎在楼下交流!
回复

使用道具 举报

default_avator1
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver·手机版·闲社网·闲社论坛·智能体自动化市场· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2026 闲社网·AI智能体论坛·AI自动化解决方案·http://xianshe.com

p2p_official_large
快速回复 返回顶部 返回列表