告别JSON依赖:如何爬取非结构化与动态网页数据**
在Web爬虫的世界里,我们常常习惯于与API打交道,享受其返回结构化JSON数据的便捷,现实中的网络远比这复杂,许多有价值的信息,如新闻文章、论坛帖子、产品详情页、学术论文等,往往以传统的HTML页面形式呈现,或者是由JavaScript动态渲染的页面,它们并不直接返回我们期望的JSON数据,面对这些“非JSON”页面,我们该如何下手呢?本文将为你详细解析爬取这类页面的多种策略与技巧。
理解“不返回JSON数据”的页面类型
我们需要明确“不返回JSON数据”的页面通常指以下几种:
- 静态HTML页面:服务器直接返回HTML文档,所有数据都在HTML标签中明确写死,这是最传统也最容易爬取的页面类型。
- 动态渲染页面:页面初始加载时可能只有少量基础HTML结构,大部分数据是通过JavaScript在客户端动态获取并渲染的,这类页面直接爬取HTML可能得不到完整数据。
- 需要交互的页面:数据可能需要用户进行点击、输入、滚动等操作后才会加载或显示。
爬取静态HTML页面的基础方法
对于静态HTML页面,爬取相对直接,核心是解析HTML并提取所需信息。
使用HTTP请求库获取HTML
我们需要发送HTTP请求获取页面的HTML内容,常用的Python库有requests。
import requests
url = "https://example.com/static-page"
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"
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 如果请求失败 (状态码非200), 则抛出异常
html_content = response.text
print("成功获取HTML内容,前500字符:")
print(html_content[:500])
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
关键点:
- 设置User-Agent:模拟浏览器访问,避免被一些简单的反爬机制拦截。
- 处理异常:网络请求可能失败,需要适当的错误处理。
- 编码问题:
response.text会自动处理编码,但有时可能需要手动指定response.encoding。
使用HTML解析库提取数据
获取HTML内容后,我们需要从中提取有用的数据,常用的HTML解析库有:
- Beautiful Soup:简单易用,适合快速解析和导航HTML/XML文档。
- lxml:性能强大,支持XPath选择器,功能更全面。
示例(使用Beautiful Soup):
from bs4 import BeautifulSoup
# 假设 html_content 已经由上面的代码获取
soup = BeautifulSoup(html_content, 'html.parser')
# 示例1:提取标题= soup.find('title').text
print(f"页面标题: {title}")
# 示例2:提取所有链接
links = soup.find_all('a')
print("页面中的所有链接:")
for link in links:
href = link.get('href')
text = link.text.strip()
if href and text:
print(f"文本: {text}, 链接: {href}")
# 示例3:通过类名提取特定内容
# 假设我们要提取class为"article-content"的div
article_content = soup.find('div', class_='article-content')
if article_content:
print("文章内容:")
print(article_content.get_text(separator='\n', strip=True))
关键点:
- 选择器:熟悉标签名、类名、ID、属性选择器以及CSS选择器或XPath。
- 导航:使用
.find(),.find_all(),.parent,.children,.siblings()等方法定位元素。 - 提取文本与属性:使用
.text或.get_text()提取文本内容,使用.get('attribute_name')提取属性值。
应对动态渲染页面的策略
对于由JavaScript动态渲染的页面,直接使用requests获取的HTML可能不包含最终呈现给用户的数据,这时我们需要更高级的工具。
使用浏览器自动化工具
这类工具通过模拟真实浏览器行为(加载JS、执行脚本、渲染页面)来获取最终渲染后的HTML。
- Selenium:最流行的浏览器自动化测试框架,也可用于爬虫,支持多种浏览器(Chrome, Firefox, Edge等)。
示例(使用Selenium + Chrome):
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
# 配置Chrome选项
chrome_options = Options()
chrome_options.add_argument("--headless") # 无头模式,不显示浏览器界面
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("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")
# 指定ChromeDriver路径 (或确保其在系统PATH中)
# service = Service(executable_path='path/to/chromedriver')
# driver = webdriver.Chrome(service=service, options=chrome_options)
driver = webdriver.Chrome(options=chrome_options) # 如果chromedriver在PATH中
url = "https://example.com/dynamic-page"
driver.get(url)
# 等待页面加载完成,可以根据实际情况调整等待方式
# 等待某个特定的元素出现
try:
# 假设我们等待id为"dynamic-content"的元素加载完成
element = driver.find_element(By.ID, "dynamic-content")
# 如果元素是异步加载的,可能需要显式等待
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "dynamic-content")))
print("动态内容加载完成")
except Exception as e:
print(f"等待元素时出错: {e}")
# 如果没有特定元素等待,可以固定等待几秒
time.sleep(3) # 简单等待,但不推荐作为首选
# 获取渲染后的HTML
rendered_html = driver.page_source
driver.quit() # 关闭浏览器
# 使用Beautiful Soup解析渲染后的HTML
soup = BeautifulSoup(rendered_html, 'html.parser')
# 现在可以提取动态加载的数据了
dynamic_data = soup.find(id='dynamic-content').text
print(f"动态加载的数据: {dynamic_data}")
关键点:
-
元素定位:熟练使用
By.ID,By.CLASS_NAME,By.XPATH,By.CSS_SELECTOR等定位元素。 -
等待策略:使用
WebDriverWait和expected_conditions进行显式等待,比固定time.sleep()更可靠。 -
无头模式:爬虫通常使用无头模式以提高效率。
-
性能:Selenium比直接
requests慢得多,应谨慎使用。 -
Playwright:微软开发的现代自动化库,支持多浏览器,API更友好,性能和稳定性较好,是Selenium的有力竞争者。
分析网络请求,直接调用API
很多动态页面数据是通过AJAX(异步JavaScript和XML/JSON)请求从后端API获取的,我们可以通过浏览器的开发者工具(F12 -> Network标签)分析这些请求,找到数据接口,然后直接模拟这些API请求获取JSON数据,这种方法效率最高,也避免了复杂的页面渲染。
步骤:
- 打开浏览器开发者工具(F12)。
- 切换到“Network”(网络)标签。
- 刷新页面或执行页面操作,观察网络请求列表。
- 筛选“XHR”或“Fetch”类型的请求,这些通常是AJAX请求。
- 查看这些请求的URL、请求方法(GET/POST)、请求头(Headers)和载荷(Payload)。
- 尝试使用
requests库模拟这些请求,获取返回的JSON数据。
示例:
假设通过分析发现数据是通过GET https://example.com/api/data?page=1获取的。
import requests
api_url = "https://example.com/api/data?page=1"
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",
# 可能还需要其他请求头,如Referer


还没有评论,来说两句吧...