这是一个相对“古老”但依然有价值的爬虫场景,因为理解其原理能帮助你应对更复杂的现代动态网页。

核心概念:Silverlight 与爬虫的矛盾
我们要明白为什么 Silverlight 网站爬起来比较麻烦。
- 客户端渲染:与传统的服务器端渲染(SSR)不同,Silverlight 应用程序是一个在用户浏览器中运行的客户端应用程序,它通过 XAML 定义界面,并通过 C# 或 VB.NET 编写业务逻辑,网页本身(HTML)只是一个“容器”,真正的内容和交互逻辑都在 Silverlight 的
.xap文件中。 - 数据加载方式:Silverlight 应用程序通常不会像传统网页那样,通过页面 URL 的变化来加载新数据,它更像一个桌面应用,通过后台的 WCF (Windows Communication Foundation) 服务 或 Web Services 来获取数据,这些服务调用通常是异步的,数据格式多为 JSON 或 XML。
- 浏览器工具的局限性:当你使用浏览器的“开发者工具”(F12)查看网络请求时,你会发现,你看到的 Silverlight 页面请求,其响应内容往往是一个空白的 HTML 页面和一个指向
.xap文件的链接,真正的数据请求(比如查询列表、获取详情)并没有在浏览器的“网络”标签页中留下记录,因为这些请求是由 Silverlight 插件在内部发起的。
直接用传统的 requests 库去请求 Silverlight 网站的页面 URL,是拿不到你想要的数据的,你需要找到并模拟它底层数据服务的 API 请求。
爬取 Silverlight 网站的两种主要方法
逆向工程(推荐,最稳定、最健壮)
这是最常用且最可靠的方法,其核心思想是:不与 Silverlight 的前端界面打交道,而是直接找到它获取数据的“数据源”(即 API 接口),然后模拟这个接口请求。
操作步骤:

-
安装浏览器开发者工具:通常按
F12或Ctrl+Shift+I(Windows) /Cmd+Opt+I(Mac) 打开。 -
定位数据请求:
- 在 Silverlight 应用程序中进行操作,比如点击“查询”、“加载下一页”等按钮。
- 切换到开发者工具的 “网络” (Network) 标签页。
- 关键一步:由于 Silverlight 的请求可能不会被浏览器捕获,你需要确保开发者工具能监控到它们,在 Chrome 中,勾选 "Preserve log" 可以防止日志被刷新清除,在 Firefox 中,"网络" 面板默认会捕获很多类型的请求。
- 筛选请求类型:在筛选框中输入
XHR(XMLHttpRequest) 或Fetch,这能帮你快速定位到异步数据请求,Silverlight 的 WCF 服务请求通常也会被归为此类。
-
分析 API 请求:
- 找到你操作后触发的那个新的网络请求,点击它,查看详细信息。
- URL:这就是你要找的 API 地址,它可能看起来很复杂,带有很多参数,
.../DataService.svc/GetList?page=1&size=20。 - 请求方法:通常是
GET或POST。 - 请求头:注意
Accept、Content-Type、User-Agent等信息,模拟请求时可能需要带上。 - 载荷/参数:如果是
POST请求,查看Payload或Request Body部分,看看发送了什么数据(可能是 JSON 格式)。 - 响应:查看
Response或Preview标签,确认返回的数据格式(通常是 JSON),并且正是你想要抓取的内容。
-
使用 Python 模拟请求:
(图片来源网络,侵删)- 一旦你找到了 API 的规律,就可以用 Python 的
requests库来模拟这个请求,直接获取数据,完全绕过 Silverlight 前端。 - 示例代码:
import requests import json # 1. 从开发者工具中复制的 API URL api_url = "http://example.com/DataService.svc/GetList" # 2. 模拟请求参数(根据实际情况构造) params = { "page": 1, "size": 20, "keyword": "python" # 假设这是一个搜索关键词 } # 3. 设置请求头(非常重要!) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Accept": "application/json, text/plain, */*", # 告诉服务器我们接受 JSON 格式 "Content-Type": "application/json;charset=UTF-8", # 如果是 POST 请求且发送 JSON 数据 # "X-Requested-With": "XMLHttpRequest", # 有些 API 会检查这个头 } try: # 4. 发送 GET 请求 (根据实际情况可能是 POST) # 如果是 POST 请求,且参数在 body 里,可以这样: # response = requests.post(api_url, json=params, headers=headers) response = requests.get(api_url, params=params, headers=headers) # 5. 检查请求是否成功 response.raise_for_status() # 如果状态码不是 200,则抛出异常 # 6. 解析 JSON 数据 data = response.json() # 7. 提取你需要的信息 # 假设返回的 JSON 结构是 {"d": [{"id": 1, "name": "Item 1"}, ...]} items = data.get("d", []) # Silverlight 经典返回格式,键为 "d" for item in items: print(f"ID: {item.get('id')}, Name: {item.get('name')}") except requests.exceptions.RequestException as e: print(f"请求失败: {e}") except json.JSONDecodeError: print("响应不是有效的 JSON 格式") - 一旦你找到了 API 的规律,就可以用 Python 的
优点:
- 稳定:不依赖页面结构,只要 API 不变,爬虫就不会因为前端样式修改而失效。
- 高效:直接获取数据,无需加载庞大的 Silverlight 插件和渲染页面。
- 隐蔽:可以轻松地设置请求头、代理等,避免被反爬。
自动化浏览器(复杂、备用方案)
如果由于某些原因(如 API 加密、需要复杂登录态),你无法找到或模拟 API,那么最后的手段就是使用自动化工具来模拟一个真实的用户操作 Silverlight 应用。
工具选择:
- Selenium:最流行的 Web 自动化测试框架,它通过驱动一个真实的浏览器(如 Chrome, Firefox)来与页面交互。
- PyAutoGUI:可以操作整个屏幕,但定位元素困难,不推荐用于网页爬取。
操作步骤:
-
安装 Selenium 和对应浏览器驱动:
pip install selenium- 下载与你浏览器版本匹配的 WebDriver(如
chromedriver),并将其所在目录添加到系统环境变量,或放在代码同目录下。
-
定位 Silverlight 中的元素:
- 这是此方法最大的难点,Silverlight 生成的元素在 DOM 树中可能没有
id或name属性,或者属性值是动态生成的。 - 你需要使用 Selenium 的
find_element方法,通过其他复杂策略来定位元素,如:XPath:最强大但也最复杂,你需要分析 Silverlight 的 XAML 结构来构造 XPath。CSS Selector:有时也可能有效。By.TagName或By.ClassName:Silverlight 元素有特定的类名。
- 这是此方法最大的难点,Silverlight 生成的元素在 DOM 树中可能没有
-
编写 Python 脚本:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time # 1. 指定 ChromeDriver 的路径 (如果不在环境变量中) # service = webdriver.chrome.service.Service(executable_path='path/to/your/chromedriver') # driver = webdriver.Chrome(service=service) # 2. 初始化浏览器 driver = webdriver.Chrome() driver.maximize_window() try: # 3. 打开 Silverlight 网站 driver.get("http://example.com/silverlight-app") # 4. 等待 Silverlight 插件加载 (非常重要!) # Silverlight 应用通常需要一些时间来初始化 print("等待 Silverlight 应用加载...") time.sleep(10) # 简单粗暴的等待,不推荐,最好用 WebDriverWait # 5. 定位并操作 Silverlight 元素 (这是最困难的部分) # 假设我们要在一个 ID 为 "searchInput" 的文本框中输入 "python" # 注意:这个 ID 是 Silverlight 内部的 ID,不是 DOM 中的 ID # 你需要通过开发者工具的 "元素" 面板,仔细分析结构来找到定位方式 # 这里只是一个示例,实际定位方式可能完全不同 search_input = driver.find_element(By.XPATH, "//div[@id='silverlightHost']/*[@id='searchInput']") search_input.send_keys("python") # 6. 点击搜索按钮 search_button = driver.find_element(By.XPATH, "//div[@id='silverlightHost']/*[@id='searchButton']") search_button.click() # 7. 等待数据加载完成 time.sleep(5) # 8. 从渲染后的页面中提取数据 # 假设数据最终被渲染到了 HTML 的某个 div 中 results = driver.find_elements(By.CLASS_NAME, "result-item") for result in results: print(result.text) except Exception as e: print(f"发生错误: {e}") finally: # 9. 关闭浏览器 driver.quit()
缺点:
- 非常脆弱:页面任何微小的改动(如元素位置、ID 变化)都可能导致爬虫崩溃。
- 性能低下:需要启动完整的浏览器,加载页面和插件,速度很慢。
- 资源消耗大:占用大量内存和 CPU。
- 难以维护:定位元素本身就是一件非常耗时且痛苦的工作。
总结与建议
| 特性 | 逆向工程 (模拟 API) | 自动化浏览器 |
|---|---|---|
| 原理 | 直接调用后端数据接口 | 模拟用户操作前端界面 |
| 稳定性 | 高 | 低 |
| 效率 | 高 | 低 |
| 实现难度 | 中等(需要抓包分析) | 高(需要定位复杂元素) |
| 资源消耗 | 低 | 高 |
| 适用场景 | 绝大多数 Silverlight 网站的数据抓取 | API 被加密、需要复杂用户交互的场景 |
最终建议:
永远优先尝试方法一(逆向工程),花时间在开发者工具的“网络”面板里找到那个真正的 API,你的工作将会事半功倍,写出的爬虫也会非常健壮。
只有在方法一完全走不通的情况下,才考虑使用方法二(自动化浏览器)作为备选方案。
