Selenium动态爬虫 - 爬取JavaScript渲染的页面

很多现代网站使用JavaScript动态渲染内容,传统的requests库无法获取这些数据。Selenium通过模拟真实浏览器,可以完美解决JavaScript渲染页面的爬取问题。

一、Selenium介绍

Selenium是自动化Web浏览器的工具,可以执行点击、输入、表单提交等操作。它启动一个真实的浏览器(如Chrome、Firefox),加载完整的页面内容,包括JavaScript渲染的部分。

适用场景:

  • 需要登录才能访问的页面
  • 使用JavaScript动态加载内容的页面
  • 需要模拟复杂用户交互的场景
  • 自动化测试Web应用

二、安装Selenium

pip install selenium

# Chrome用户需要下载ChromeDriver
# 访问 https://sites.google.com/chromedriver/
# 下载对应版本的ChromeDriver

三、基本用法

from selenium import webdriver

# 启动Chrome浏览器
driver = webdriver.Chrome()

# 访问网页
driver.get('https://www.example.com')

# 获取页面标题
print(driver.title)

# 获取页面源码
print(driver.page_source[:500])

# 获取当前URL
print(driver.current_url)

# 关闭浏览器
driver.quit()

四、元素定位

Selenium提供了多种元素定位方式:

from selenium.webdriver.common.by import By

# 各种定位方式
driver.find_element(By.ID, "content")          # ID定位
driver.find_element(By.NAME, "username")         # NAME定位
driver.find_element(By.CLASS_NAME, "container") # CLASS_NAME定位
driver.find_element(By.TAG_NAME, "div")        # 标签名定位
driver.find_element(By.XPATH, "//div[@class='container']")  # XPath定位
driver.find_element(By.CSS_SELECTOR, "div.container")  # CSS选择器定位
driver.find_element(By.LINK_TEXT, "点击这里")    # 链接文本定位
driver.find_element(By.PARTIAL_LINK_TEXT, "点击")  # 部分链接文本

# 查找所有匹配的元素(返回列表)
links = driver.find_elements(By.TAG_NAME, "a")

五、等待机制

动态页面需要等待元素加载完成:

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, "content"))
)

# 常用等待条件
EC.title_is("首页")                          # 标题等于
EC.title_contains("首页")                      # 标题包含
EC.presence_of_element_located((By.ID, "id"))  # 元素出现
EC.visibility_of_element_located((By.ID, "id"))  # 元素可见
EC.element_to_be_clickable((By.ID, "id"))     # 元素可点击

# 隐式等待(全局设置)
driver.implicitly_wait(10)  # 查找元素最多等10秒

六、模拟操作

from selenium.webdriver.support.select import Select

# 点击元素
driver.find_element(By.ID, "submit").click()

# 输入文本
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("Python爬虫")  # 输入文本

# 清除输入
search_box.clear()

# 下拉选择
select = Select(driver.find_element(By.NAME, "dropdown"))
select.select_by_visible_text("选项1")  # 按显示文本选择
select.select_by_value("option1")        # 按value选择
select.select_by_index(0)               # 按索引选择

# 拖拽元素
from selenium.webdriver import ActionChains
draggable = driver.find_element(By.ID, "draggable")
droppable = driver.find_element(By.ID, "droppable")
ActionChains(driver).drag_and_drop(draggable, droppable).perform()

# 执行JavaScript
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")  # 滚动到底部
driver.execute_script("alert('Hello')")  # 执行JS代码

七、获取数据

element = driver.find_element(By.ID, "content")

# 获取文本
print(element.text)           # 元素内所有文本

# 获取属性
print(element.get_attribute('href'))   # 获取href属性
print(element.get_attribute('class'))  # 获取class属性
print(element.get_attribute('innerHTML'))  # 获取HTML

# 获取CSS样式
print(element.value_of_css_property('color'))
print(element.value_of_css_property('font-size'))

八、Cookie和窗口管理

# 获取Cookie
cookies = driver.get_cookies()
print(cookies)

# 添加Cookie
driver.add_cookie({'name': 'session', 'value': 'abc123'})

# 删除Cookie
driver.delete_cookie('session')
driver.delete_all_cookies()

# 切换窗口/标签页
driver.switch_to.window(driver.window_handles[1])  # 切换到第二个标签页
driver.close()  # 关闭当前标签页
driver.switch_to.window(driver.window_handles[0])  # 切换回第一个

# 切换frame
driver.switch_to.frame("frame_name_or_id")
driver.switch_to.default_content()  # 切换回主文档

九、实践案例

模拟登录并爬取数据:

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

def login_and_scrape():
    driver = webdriver.Chrome()
    driver.get('https://www.example.com/login')
    
    # 显式等待登录框出现
    wait = WebDriverWait(driver, 10)
    username = wait.until(
        EC.presence_of_element_located((By.NAME, "username"))
    )
    
    # 输入账号密码
    username.send_keys('your_username')
    driver.find_element(By.NAME, 'password').send_keys('your_password')
    
    # 点击登录按钮
    driver.find_element(By.XPATH, "//button[@type='submit']").click()
    
    # 等待登录成功后的页面
    wait.until(EC.url_contains('/dashboard'))
    
    # 爬取数据
    data = driver.find_elements(By.CLASS_NAME, 'data-item')
    for item in data:
        print(item.text)
    
    driver.quit()

login_and_scrape()

十、常见问题和技巧

  • ChromeDriver版本不匹配 - 下载与Chrome版本对应的ChromeDriver
  • 提高稳定性 - 总是使用显式等待而非隐式等待
  • 处理弹窗 - 使用driver.switch_to.alert()处理alert
  • 无头模式 - headless=True不显示浏览器窗口
  • 反检测 - 禁用自动化标记webdriver

十一、总结

Selenium是爬取JavaScript渲染页面的利器,但相比requests速度较慢。建议:需要登录或渲染页面时使用Selenium,普通页面用requests+BeautifulSoup组合。

发表回复

后才能评论