爬虫必踩坑:页面明明有视频链接,为什么爬虫解析不到?(AJAX动态生成真相)
前言:刚入门爬虫的朋友,大概率会遇到这样的困惑------浏览器页面上能正常看到视频链接,甚至"检查"元素也能找到,可用requests请求页面、再用XPath/BS4解析时,却死活拿不到链接。结合自己的踩坑经历,今天就把这个核心知识点讲透,帮大家避开这个高频误区。
一、先明确核心问题:你看到的,≠ 爬虫看到的
很多新手会混淆两个关键概念,这也是踩坑的根源------浏览器"检查"(Elements)看到的页面,和网页"源代码"(View Page Source)完全不同,而爬虫拿到的,只是后者。
1. 浏览器"检查"(Elements):最终渲染后的页面
当你打开视频页面,按F12打开开发者工具,切换到「Elements」面板,看到的是浏览器执行完所有JS、加载完所有动态内容后的最终页面。
这里面包含:
- 原始HTML结构
- CSS样式
- JS动态生成的DOM元素(包括视频链接)
- AJAX请求加载的所有数据
所以你在这里能看到视频链接,是完全正常的------这是浏览器"加工"后的结果。
2. 网页"源代码"(View Page Source):服务器返回的原始HTML
右键点击页面,选择「查看网页源代码」,能看到页面加载的所有信息(包括AJAX请求加载的数据)------这些数据是浏览器执行JS、发送AJAX后追加的,并非服务器第一次返回的原始内容;而爬虫用requests.get(url)只能获取这份"空壳"原始HTML,无法获取后续追加的内容,这就是爬虫爬不到视频链接的核心原因。
二、核心真相:视频链接是AJAX动态生成的,爬虫不"执行"JS
为什么页面上能看到视频链接,爬虫却拿不到?核心原因就在于:视频链接不是一开始就写在HTML里的,而是JS通过AJAX请求动态获取、再插入到页面中的,而爬虫(requests)不会执行JS,也不会主动发送AJAX请求。
完整流程拆解(一看就懂):
- 你用浏览器打开视频页面 → 浏览器向服务器发送请求;
- 服务器返回「空壳HTML」(没有视频链接,只有基础结构);
- 浏览器加载完空壳HTML后,自动执行页面中的JS代码;
- JS代码发送AJAX请求,向服务器获取视频相关数据(包含真实视频链接);
- 服务器返回视频数据,JS将视频链接插入到页面的DOM中;
- 你在浏览器「Elements」面板中看到视频链接,视频正常播放。
而爬虫的流程只有1-2步:请求页面 → 获取空壳HTML,没有后续的JS执行和AJAX请求,自然拿不到视频链接。
三、为什么XPath、BeautifulSoup解析不到?
很多人会习惯性用lxml的etree写XPath,或者用BeautifulSoup解析页面,结果一无所获,原因很简单:
XPath和BeautifulSoup,只能解析"静态HTML",不能执行JS,也不能识别JS中的内容。
举个例子:视频链接藏在JS代码里,格式如下:
javascript
// 这是JS代码,不是HTML标签
let videoInfo = {
title: "爬虫教程",
url: "https://xxx.com/xxx.mp4" // 真实视频链接
};
这种情况下,XPath 和 BS 4 只会解析 HTML 标签(比如<div>、<p>),根本不会去解析 JS 代码里的字符串,所以无论怎么写表达式,都找不到这个视频链接。
四、解决方案:3 种方法,轻松拿到动态视频链接
针对这种AJAX动态生成的视频链接,分享3种实用方法,从简单到复杂,可按需选择。
方法1:抓包找到AJAX接口(推荐,最高效)
这是最推荐的方法,不需要复杂操作,直接获取视频链接的源头,步骤如下:
- 打开视频页面,按F12打开开发者工具,切换到「Network」面板;(记得勾选保留日志)
- 点击「刷新」按钮,再点击播放视频,让浏览器触发AJAX请求;
- 在「Network」面板的搜索框中,输入关键词筛选(常用:mp4、m3u8、video、api、play);
- 找到对应的请求(一般是XHR类型),点击进入,查看「Response」(响应);
- 如果响应是JSON格式,里面大概率会有videoUrl、url等字段,直接提取即可;如果是直接返回视频链接,复制链接就能使用。
示例代码(获取接口返回的JSON数据,提取视频链接):
python
import requests
# 抓包得到的AJAX接口地址
api_url = "https://xxx.com/api/getVideoInfo?id=123"
# 请求接口(注意:有些接口需要携带headers,模拟浏览器)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
response = requests.get(api_url, headers=headers)
# 解析JSON,提取视频链接
video_url = response.json()["data"]["url"]
print("真实视频链接:", video_url)
方法2:使用能执行JS的爬虫工具(适合复杂场景)
如果AJAX接口加密、难以抓包,可使用能模拟浏览器的工具,它们会自动执行JS、加载动态内容,相当于"用代码模拟人操作浏览器",常用工具:Selenium、Playwright。
- 优势:不用抓包,直接获取浏览器渲染后的页面,就能用XPath/BS4解析视频链接;
- 劣势:速度比requests慢,配置稍复杂。
方法3:正则表达式提取JS中的链接(兜底方案)
如果视频链接直接写在JS代码里(没有通过AJAX接口获取),可通过正则表达式,从JS字符串中匹配提取链接,示例代码:
python
import requests
import re
# 请求视频页面,获取原始HTML(包含JS代码)
url = "https://xxx.com/video/123"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers)
# 用正则匹配JS中的视频链接(匹配规则根据实际JS代码调整)
# 示例:匹配 let videoUrl = "https://xxx.mp4" 中的链接
pattern = re.compile(r'videoUrl\s*=\s*["\'](.*?)["\']', re.S)
result = pattern.search(response.text)
if result:
video_url = result.group(1)
print("提取到的视频链接:", video_url)
else:
print("未找到视频链接")
五、核心总结(必记)
-
页面上能看到的视频链接,是浏览器执行JS、发送AJAX后动态插入的,不是原始HTML自带的;
-
requests爬虫只获取原始HTML,不执行JS、不发送AJAX,所以拿不到动态链接;
-
XPath/BS4只能解析静态HTML,无法解析JS中的内容;
-
最优解:抓包找AJAX接口;复杂场景:用Selenium/Playwright;兜底:正则提取JS中的链接。
六、避坑提醒
-
不要混淆「Elements」和「网页源代码」,爬虫拿到的是后者;
-
遇到"页面有、爬虫无"的情况,优先考虑AJAX动态加载;
-
抓包时,记得携带headers(User-Agent等),避免被服务器识别为爬虫。
如果大家在实际操作中遇到抓包困难、正则匹配不到等问题,可以评论区留言,一起交流解决~