Python 爬虫与 JavaScript 的关系
Python 爬虫本身不直接执行 JavaScript,Python 的标准库(如 urllib)和流行的第三方库(如 Requests)只能获取到服务器返回的初始 HTML 代码。

而现代网页(特别是单页应用 SPA)大量使用 JavaScript 来动态加载内容,这意味着你用 requests 获取到的 HTML 可能只是一个“空架子”,真正的数据是通过 JavaScript 在浏览器中运行后才渲染出来的。
当爬虫遇到由 JavaScript 生成内容的网页时,如果只使用 requests,就会获取不到最终看到的数据,导致爬取失败或爬取到空数据。
为什么网页需要 JavaScript?
- 加载:用户滚动页面时加载更多内容(无限滚动)。
- 单页应用:整个网站只有一个 HTML 页面,通过 JavaScript 动态切换视图(如 Gmail, Twitter)。
- 异步数据请求:页面加载完成后,再通过 AJAX/Fetch API 向服务器请求数据并更新页面。
- 复杂的用户交互:点击按钮、拖拽、输入框实时验证等。
爬取由 JavaScript 渲染的网页的几种方法
面对这种情况,我们有以下几种主流的解决方案,从简单到复杂排列:
分析网络请求(最推荐,最高效)
这是首选且最优雅的解决方案,核心思想是:让浏览器替我们执行 JavaScript,然后我们只关心最终的数据是从哪里来的。

操作步骤:
- 打开浏览器开发者工具:按
F12或Ctrl+Shift+I(Windows) /Cmd+Opt+I(Mac)。 - 切换到 "Network" (网络) 标签页。
- 刷新或操作网页:比如点击“加载更多”按钮,或者滚动页面。
- 分析请求列表:在请求列表中,找到那些返回了 JSON 或其他格式数据的请求,这些请求的 URL 和响应内容通常就是网页上显示的数据。
- 验证请求:点击某个请求,查看它的 "Headers"(请求头)和 "Response"(响应体),如果响应体是 JSON 格式,并且包含了你想要爬取的数据,那么你就找到了目标 API。
- 用 Python 模拟请求:使用
requests库,直接向这个 API 的 URL 发送请求,并带上必要的请求头(如User-Agent,Referer,Cookie等)。
优点:
- 速度快:直接获取结构化的数据(如 JSON),无需解析整个 HTML。
- 效率高:数据量小,网络传输快,解析简单。
- 稳定:只要网站后端 API 不变,爬虫就不受前端 JavaScript 代码改动的影响。
示例:
假设你在开发者工具中发现了一个 API 请求 https://example.com/api/data,返回了 JSON 数据。

import requests
import json
# 目标 API URL
api_url = "https://example.com/api/data"
# 伪造请求头,模拟浏览器行为
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, */*",
"Referer": "https://example.com/" # 可能需要 Referer 来绕过防盗链
}
try:
response = requests.get(api_url, headers=headers)
response.raise_for_status() # 如果请求失败,则抛出异常
# 解析 JSON 数据
data = response.json()
# 处理数据
for item in data['results']:
print(f"ID: {item['id']}, Title: {item['title']}")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except json.JSONDecodeError:
print("响应不是有效的 JSON 格式")
使用无头浏览器(终极武器)
当分析网络请求无法解决问题时(例如数据被加密、请求极其复杂或有反爬虫机制),我们就需要使用无头浏览器,它是一个没有图形界面的浏览器,可以完全模拟一个真实用户的行为,包括执行 JavaScript。
常用库:
- Selenium:老牌、功能强大、社区活跃,支持多种浏览器(Chrome, Firefox 等)。
- Playwright:微软出品, newer, faster, and more reliable,API 更现代化,性能更好,是 Selenium 的强力竞争者。
工作原理: Python 代码启动一个无头浏览器,让它打开网页,等待 JavaScript 执行完毕,然后获取渲染后的完整 HTML 源代码,最后再用 BeautifulSoup 或 lxml 等库进行解析。
示例 (使用 Selenium + Chrome):
-
安装依赖:
pip install selenium # 还需要下载对应浏览器的 WebDriver,如 ChromeDriver # Selenium 4+ 可以自动管理,但有时需要手动指定路径
-
Python 代码:
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("--window-size=1920,1080")
# 初始化 WebDriver (Selenium 4 会自动下载和管理驱动,但指定路径更稳定)
# service = Service(executable_path='path/to/your/chromedriver')
# driver = webdriver.Chrome(service=service, options=chrome_options)
driver = webdriver.Chrome(options=chrome_options)
try:
# 1. 打开目标网页
url = "https://example.com/dynamic-content"
driver.get(url)
# 2. 等待 JavaScript 渲染 (关键步骤!)
# 可以用 time.sleep() 简单粗暴地等待
time.sleep(5)
# 或者更智能地等待某个元素出现
# 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.CSS_SELECTOR, ".data-item")))
# 3. 获取渲染后的页面源代码
page_source = driver.page_source
# 4. 使用 BeautifulSoup 解析 HTML
soup = BeautifulSoup(page_source, 'html.parser')
# 5. 提取数据
items = soup.find_all('div', class_='data-item')
for item in items:
title = item.find('h2').text
print(title)
finally:
# 6. 关闭浏览器
driver.quit()
优点:
- 万能:能处理任何由 JavaScript 渲染的网页。
- 真实:模拟真实用户行为,可以绕过一些基于行为的反爬虫。
缺点:
- 速度慢:启动浏览器、加载页面、执行 JS 都非常耗时。
- 资源消耗大:会占用大量 CPU 和内存。
- 维护成本高:网页结构或前端代码的微小改动都可能导致爬虫失效。
总结与选择
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 分析网络请求 | 快、准、稳、资源消耗低 | 不是所有网站都适用 | 首选方案,适用于绝大多数现代网站,特别是 SPA 和无限滚动页面。 |
| 无头浏览器 | 万能、能模拟真实用户 | 慢、资源消耗大、不稳定 | 当分析网络请求失败时的备选方案,适用于页面交互复杂、数据被动态加密或请求参数难以复制的网站。 |
最佳实践
- 永远先尝试方法一(分析网络请求),这是爬虫工程师的必备技能,能解决 80% 的问题。
- 如果方法一失败,再考虑使用方法二(无头浏览器)。
- 结合使用:有时可以先通过无头浏览器登录或进行一些操作,然后获取 Cookie,再用
requests去请求 API,兼顾效率和稳定性。 - 设置合理的
User-Agent:无论是requests还是 Selenium,都应设置一个常见的浏览器User-Agent,避免被轻易识别为爬虫。 - 处理反爬机制:注意处理网站的 IP 封禁、验证码、动态 Cookie 等反爬策略。
希望这个详细的解释能帮助你理解 Python 爬虫与 JavaScript 的关系,并掌握应对之道!
