第4章 动态数据采集:Selenium入门、浏览器自动化、处理JavaScript渲染页面

4.1 为什么需要Selenium?

说实话,做数据采集最头疼的不是数据量大,而是页面不配合。你想想看,很多网站现在都是JavaScript渲染的——数据不是写在HTML里,而是通过JS动态加载出来的。你用requests去抓,拿到的只是一堆空壳子。

我刚开始做采集时,就踩过这个坑。一个电商网站的商品列表,用requests死活抓不到数据,折腾了两天才发现是JS渲染的。后来改用Selenium,十分钟搞定。嗯,工具选对了,事半功倍。

Selenium说白了就是一个浏览器自动化工具。它能模拟真实用户的操作——打开网页、点击按钮、滚动页面、填写表单。最关键的是,它能等JavaScript执行完再拿数据。

核心概念:Selenium通过WebDriver驱动真实的浏览器(Chrome、Firefox等),让浏览器像真人一样操作页面。这样JS渲染的内容自然就能拿到了。

4.2 环境搭建

安装其实很简单,就两步。我个人习惯用Chrome,因为调试工具顺手。

# 第一步:安装Selenium库
pip install selenium

# 第二步:下载ChromeDriver
# 注意版本要和你的Chrome浏览器一致
# 下载地址:https://chromedriver.chromium.org/

避坑指南:我曾经因为ChromeDriver版本不对,折腾了一下午。Chrome浏览器会自动更新,但Driver不会。建议用代码自动匹配版本,或者定期检查。

写个简单的启动代码,验证环境是否正常:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# 配置浏览器选项
options = Options()
options.add_argument('--headless')  # 无头模式,不显示浏览器窗口

# 启动浏览器
driver = webdriver.Chrome(options=options)
driver.get('https://www.baidu.com')

print(driver.title)  # 打印页面标题
driver.quit()        # 关闭浏览器

跑通了?好,那我们继续。

4.3 核心操作:定位元素

Selenium最常用的就是定位页面元素。说白了,就是告诉浏览器「我要找那个按钮」、「我要找那个输入框」。

我常用的定位方式有8种,但实际工作中80%的情况只用两种:

定位方式 写法示例 适用场景
ID定位 find_element(By.ID, 'username') 元素有唯一ID时,最快最稳
CSS选择器 find_element(By.CSS_SELECTOR, '.class-name') 没有ID时,用class或属性定位
XPath find_element(By.XPATH, '//div[@class="item"]') 结构复杂时,XPath最灵活
文本定位 find_element(By.LINK_TEXT, '下一页') 定位链接或按钮文本

我的经验:优先用ID,没有ID用CSS选择器。XPath虽然强大,但写起来啰嗦,而且页面结构一变就容易失效。我在项目中吃过这个亏,后来尽量少用XPath。

4.4 等待机制:别急着拿数据

这是新手最容易犯的错误。你让浏览器打开一个页面,然后立刻去拿数据——但JS还没执行完呢!

为什么会这样?因为浏览器加载页面是异步的。HTML先到,JS后执行。如果你不等JS渲染完,拿到的就是空数据。

Selenium提供了两种等待方式:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 方式一:显式等待(推荐)
# 等到某个元素出现再继续
wait = WebDriverWait(driver, 10)  # 最多等10秒
element = wait.until(
    EC.presence_of_element_located((By.ID, 'data-list'))
)

# 方式二:隐式等待(全局设置)
# 每次查找元素时,如果没找到就等一会儿
driver.implicitly_wait(5)  # 全局等5秒

核心建议:我个人习惯用显式等待。隐式等待虽然方便,但有时候会掩盖真正的问题。比如页面加载失败,隐式等待会傻等5秒,而显式等待能立刻报错。

4.5 实战:采集动态加载的新闻列表

来,我们写个完整的例子。假设有个新闻网站,列表是JS动态渲染的:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# 启动浏览器
driver = webdriver.Chrome()
driver.get('https://example-news.com/list')

# 等待列表加载完成
wait = WebDriverWait(driver, 10)
news_list = wait.until(
    EC.presence_of_element_located((By.CLASS_NAME, 'news-items'))
)

# 获取所有新闻条目
items = driver.find_elements(By.CSS_SELECTOR, '.news-item')

data = []
for item in items:
    title = item.find_element(By.CSS_SELECTOR, '.title').text
    link = item.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')
    date = item.find_element(By.CSS_SELECTOR, '.date').text
    
    data.append({
        'title': title,
        'link': link,
        'date': date
    })

# 翻页采集
while True:
    try:
        next_btn = driver.find_element(By.LINK_TEXT, '下一页')
        next_btn.click()
        time.sleep(2)  # 等页面加载
        
        # 继续采集...
        items = driver.find_elements(By.CSS_SELECTOR, '.news-item')
        for item in items:
            # 同上,采集数据
            pass
            
    except:
        print("没有下一页了")
        break

driver.quit()
print(f"共采集 {len(data)} 条数据")

避坑指南:我曾经在翻页时没加time.sleep,结果点击太快,页面还没加载完就报错了。虽然显式等待能解决大部分问题,但翻页这种操作,加个1-2秒的固定等待更稳妥。

4.6 处理常见问题

做自动化采集,总会遇到各种幺蛾子。我整理了几个高频问题:

  • 元素被遮挡:有时候元素在页面上,但被其他元素挡住了。用ActionChains模拟鼠标移动过去再点击。
  • 弹窗干扰:突然弹出广告或验证码。用driver.switch_to.alert处理弹窗,或者用try-except跳过。
  • 页面滚动加载:有些页面是滚动到底部才加载新内容。用driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')模拟滚动。
  • 反爬检测:网站检测到是自动化工具,直接封IP。可以加options.add_argument('--disable-blink-features=AutomationControlled')隐藏特征。

重要提醒:采集数据要遵守网站的robots.txt协议,不要频繁请求。我一般会在每次请求之间加2-5秒的延迟,既保护自己,也不给服务器造成压力。

4.7 本章知识体系

下面这张图,是我自己总结的Selenium采集流程。你照着这个思路走,基本不会出错:

Selenium动态数据采集流程 1. 环境准备 安装Selenium + Driver 2. 启动浏览器 配置Options + WebDriver 3. 打开目标页面 driver.get(url) 4. 等待JS渲染 显式/隐式等待 5. 定位元素 ID/CSS/XPath 6. 提取数据 .text / .get_attribute() 7. 翻页/滚动 循环采集更多数据 8. 保存数据 CSV/JSON/数据库 9. 关闭浏览器 driver.quit() 核心原则:先等渲染,再取数据,慢一点反而更快

4.8 小结

Selenium入门其实不难,核心就三点:

  • 等渲染:别急着拿数据,等JS跑完再说
  • 准定位:选对定位方式,优先ID和CSS
  • 稳操作:加延迟、处理异常、隐藏自动化特征

我在实际项目中,用这套方法采集过几十个动态网站的数据。只要不是遇到特别变态的反爬,基本都能搞定。记住,做采集不是比谁快,而是比谁稳。慢一点,反而能跑得更远。

可可精品资料库