requests拿不到页面数据是因为它不执行javascript,仅获取初始html;动态内容需用selenium等浏览器自动化工具或直接调用xhr/fetch接口。

为什么 requests 拿不到页面里显示的数据
因为数据是通过 JavaScript 在浏览器里异步加载的,requests 只能拿到初始 HTML,不执行 JS,所以 document.querySelectorAll('.item') 对应的元素在源码里根本不存在。你用浏览器“查看网页源代码”看到的和“检查元素”看到的不一样,就是这个原因。
- 典型表现:用
requests.get(url).text搜索某个商品标题或列表 ID,结果为空 - 本质区别:
requests是 HTTP 客户端,Selenium是浏览器控制器 - 不是所有动态加载都必须用 Selenium——先用浏览器 Network 面板过滤
XHR或Fetch,看能不能直接调 API;能绕开就别上浏览器自动化
启动 ChromeDriver 的三个关键配置
默认启动的 Chrome 会弹窗、带开发者工具栏、加载扩展,这些不仅慢,还容易被目标网站识别为自动化流量。必须显式禁用:
- 加
--headless=new(注意不是旧版--headless)才能真无界面,否则可能卡住或报chrome not reachable - 加
--no-sandbox和--disable-dev-shm-usage,尤其在 Docker 或 Linux 服务器上,否则大概率启动失败 - 加
--disable-blink-features=AutomationControlled并配合 JS 注入隐藏navigator.webdriver,否则很多站点会返回 403 或空白页
示例初始化片段:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opts = Options()
opts.add_argument("--headless=new")
opts.add_argument("--no-sandbox")
opts.add_argument("--disable-dev-shm-usage")
opts.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=opts)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
等待元素出现不能只靠 time.sleep()
time.sleep(3) 看似简单,实际极不可靠:网络快时浪费时间,慢时又拿不到元素,还掩盖真实问题。Selenium 提供了显式等待机制,核心是 WebDriverWait + expected_conditions。
- 优先用
presence_of_element_located(元素出现在 DOM)而不是visibility_of_element_located(还要渲染可见),后者对懒加载图片/折叠区域容易超时 - 超时设为 10 秒足够,设太长会让整个爬虫流程拖沓;设太短(如 2 秒)可能因 CDN 延迟误判失败
- 避免在循环里反复调
find_element而不等——应该先等容器出现,再在其内部查子元素,减少定位失败概率
比如等商品列表加载完成:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By wait = WebDriverWait(driver, 10) items = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".product-list"))) product_elements = items.find_elements(By.CSS_SELECTOR, ".product-item")
关闭 driver 的时机和副作用
很多人在每次请求后调 driver.quit(),以为更“干净”,其实反而低效:启动浏览器耗时约 800–1500ms,频繁启停让吞吐量骤降。正确做法是复用单个 driver 实例,但要注意状态残留。
- 每次跳转新 URL 前,用
driver.get(url)或driver.navigate().to(url),不要依赖location.hrefJS 跳转,否则等待逻辑可能失效 - 页面间切换时,手动清空 localStorage / sessionStorage(用
driver.execute_script("window.localStorage.clear()")),防止登录态或筛选条件污染下一页 - 程序结束前再
quit();若中途异常退出,建议用try/finally包裹确保关闭,否则残留进程会吃光内存
真正容易被忽略的是:ChromeDriver 进程有时会僵死(尤其是 headless 下崩溃后),ps aux | grep chromedriver 手动清理过几次,你就记得加 atexit.register(driver.quit) 了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











