你肯定有过这种体验:刷微博的时候,手指一个劲往下滑,新的帖子就自动冒出来了,整个过程中,页面没刷新,地址栏也没变,但就是能看到更多内容。
再比如,你在淘宝搜“运动鞋”,筛选价格、挑销量排序,页面内容明明变了,但浏览器也没转圈重新加载,一秒就切换好了。
其实这背后,都有一个“幕后大佬”在帮忙——它就是AJAX。很多人一听这个名字就头大,觉得是高深的技术,其实一点都不复杂。

AJAX:不用刷新页面,也能更新内容
AJAX的全称是Asynchronous JavaScript and XML,翻译过来是“异步的JavaScript和XML”。名字看着唬人,但用大白话讲,就特别好理解:
让网页不用重新加载整个页面,就能偷偷和服务器交换数据,只更新页面里需要变的那一块内容。
我再给大家举个通俗的例子:把网页比作你家的房子,以前想换个家具,得把整栋楼拆了重新建,特别麻烦;现在有了AJAX,想换张桌子就只换桌子,椅子、沙发、墙壁都不动,省时又省力。
可能有人会问,什么叫“异步”?简单说就是,AJAX请求是在后台悄悄进行的,不耽误你做别的。你该刷网页、点按钮就正常操作,数据在后台默默加载,等加载好了,网页就自动把新内容填上去,一点都不影响你的使用。
至于名字里的XML,大家不用太在意——这是早期用来传输数据的格式,现在基本都被JSON取代了,名字里还留着它,纯属历史遗留问题,不用深究。
传统爬虫的“坑”:看不见动态加载的内容
很多新手刚开始写爬虫,比如用Python的requests库,直接去拿网页的源代码,代码大概长这样:
import requests
response = requests.get('https://example.com')
print(response.text)但这样拿到的,只是服务器第一次返回的HTML源码,相当于只有网页的“空架子”。那些靠AJAX动态加载的内容,比如微博的评论、淘宝的商品列表、刷不完的动态,在这个初始源码里,根本找不到。
就好比你去餐厅吃饭,服务员先给你上了一张空桌子,而你点的菜(动态内容),得等后厨做好了(AJAX请求加载完成),才会端上来。你只看空桌子,自然看不到菜。
这也是很多新手会卡住的地方:明明在浏览器里看得清清楚楚的内容,为什么用爬虫爬出来的源码里,连影子都没有?其实问题就出在AJAX上——你爬的是“空桌子”,而菜还没端上来。
三种破解方法(从易到难,新手也能学会)
方法一:直接抓AJAX请求(最推荐,最省事)
这是最聪明、最高效的办法,不用绕弯子,直接找到网页加载数据的“源头”。步骤很简单:打开浏览器,按F12调出开发者工具,切换到“Network(网络)”标签,勾选“XHR”或者“Fetch”,然后去触发加载更多内容(比如往下滑微博、点击“加载更多”)。
这时候你会发现,列表里会多出一些请求,有些是以.json结尾的,或者点开后,在“Preview”(预览)里能看到规整的数据——这就是AJAX请求拿到的数据,已经是整理好的格式,连解析都省了,直接用就行。
给大家举个实际例子,比如爬微博评论区。打开微博评论页,按F12,往下滚动加载更多评论,就能找到一个和“comments”相关的请求,复制它的URL,然后用requests模拟这个请求,加上请求头(尤其是Referer和User-Agent,相当于告诉网站“我是正常浏览器访问,不是爬虫”),就能轻松拿到评论数据。
代码参考这样:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 ...', # 这里填自己浏览器的User-Agent
'Referer': 'https://weibo.com' # 告诉网站你从哪个页面来的
}
url = 'https://weibo.com/api/comments?id=123456' # 复制的评论请求URL
data = requests.get(url, headers=headers).json() # 直接拿到JSON格式的数据优点很明显:速度快、省内存,拿到的数据还规整;缺点就是,有些网站会给请求参数加密(比如加token、sign),需要多花点时间分析参数。
方法二:用Selenium模拟浏览器(笨办法,但万能)
如果遇到那种AJAX请求特别复杂,参数加密得看不懂,没法直接抓请求的情况,就用笨办法——让爬虫真的打开一个浏览器,像人一样操作。
Selenium就相当于一个机器人,能控制Chrome、Firefox这些浏览器,自动访问网页、滚动页面、点击按钮,它会自动执行所有AJAX请求,等所有内容都加载完,再把完整的页面内容交给你,你直接爬就行。
代码参考这样:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome() # 打开Chrome浏览器
driver.get('https://example.com') # 访问目标网页
time.sleep(3) # 等3秒,给AJAX足够的加载时间
content = driver.page_source # 拿到加载完所有内容的页面源码
driver.quit() # 关闭浏览器优点是:几乎能搞定所有动态页面,不用费脑分析请求参数,新手也能上手;缺点也很明显:速度慢、特别耗内存,而且容易被网站检测到是爬虫(可以加个stealth.min.js文件,规避检测)。
方法三:分析数据接口+代理IP(解决被封IP的问题)
有时候,你就算找到了AJAX接口,连续发几次请求后,就会发现被网站封IP了——要么提示“请求过于频繁”,要么直接返回403错误,再也爬不到数据了。
这时候,之前提到的代理IP就派上大用场了。代理IP相当于一个中间服务器,你的请求先发给它,再由它转发给目标网站。这样一来,网站看到的就不是你的真实IP,而是代理的IP,换一个代理,就相当于换了一个身份,网站就认不出你了。
代码参考这样:
import requests
proxies = {
'http': 'http://127.0.0.1:8080',
'https': 'http://127.0.0.1:8080'
}
response = requests.get(url, headers=headers, proxies=proxies) # 加上代理请求给大家一个实用建议:准备一个代理池,里面放几十到几百个代理IP,每次请求的时候随机选一个,再把请求频率控制在每秒1-2次,这样既能稳定爬数据,又不容易被网站封锁。
另外提醒一句,付费代理比免费代理稳定多了,要是爬重要数据,花点钱买付费代理,能省很多麻烦,性价比很高。
实战小技巧:用“无限滚动”网站练手,快速上手
新手想练手的话,找一个无限滚动的网站(比如某些新闻站、图片站),打开F12→Network→XHR,然后往下滚动页面,观察新出现的请求。找到一个请求后,复制它的cURL命令,用curlconverter这个工具,把cURL转换成Python代码,基本就能直接运行,轻松拿到数据。
多练个两三次你就会发现,80%的动态网站,都能用“找AJAX接口”这个方法解决,剩下的20%,用Selenium兜底,基本不会翻车。
总结
- AJAX没那么复杂,就是网页在后台偷偷拿数据、局部刷新,你用着没感觉而已;
- 传统爬虫只能拿到网页的初始“空架子”,抓不到AJAX加载的动态内容;
- 破解动态网页的3个方法,按优先级来:
1. 优先找XHR/JSON接口,最轻量、最高效;
2. 接口太复杂,就用Selenium模拟浏览器,笨但万能;
3. 被封IP,就用代理IP换身份,稳定爬取不翻车。
其实动态内容一点都不可怕,只是比静态网页多了一步“前端偷偷拿数据”的操作。你的爬虫只要学会“等一等”(等AJAX加载),或者“找对门”(找到AJAX接口),就能把那些藏起来的数据,稳稳当当地拿到手。
