Python中如何使用Selenium+PhantomJS加载ajax数据

如今的网站有两种。一种是同步加载的。另一种是异步加载的,也即我们常说的用ajax。对于那种同步加载的网站,普通的爬虫程序轻轻松松的就能搞定。但是对于那种异步请求数据的网站,就不能走寻常路了。对于这种情况,通常的解决方案是使用selenimu+PhantomJS组合来完成。有的童鞋可能还不是很了解这两者之间的关系,接下来做个简单介绍:

  1. selenium:是一个web的自动化测试工具,最初是为网站自动化测试而开发的.我们可以通过他使用代码来操作浏览器以及其中的网页元素。selenium支持绝大部分的浏览器,以及类似PhantomJS这种无界面的浏览器。

  2. PhantomJS:是一个基于Webkit的“无界面”(headless)浏览器。他除了没有界面,其他功能跟普通浏览器是一样的。也正因为他没有界面,因此运行效率比普通浏览器要高。

PhantomJS 安装:

http://phantomjs.org/下载合适自己电脑版本的PhantomJS。然后根据自己的操作系统配置其环境变量。比如mac或者linux,可以把PhantomJS放置在/usr/bin或者/usr/local/bin中。而windows用户也可以在我的电脑->属性->环境变量中配置好PhantomJS所在的路径。

selenium 使用介绍:

  1. 安装:sudo pip install selenium

  2. 使用以下代码做个简单介绍.这篇教程不打算对selenium做细节的讲解。如果想要详细了解使用细节,可以访问http://selenium-python.readthedocs.io/或者关注本公众号找我索要教程:

# 导入 webdriver 对象
from selenium import webdriver
# 初始化 PhantomJS 浏览器
driver = webdriver.PhantomJS()
# 访问百度
driver.get('http://www.baidu.com/')

获取 id 为 wrapper 这个元素的 text

driver.find_element_by_id(“wrapper”).text …

获取豆瓣热门排行版的电影数据

豆瓣热门电影的数据,不是一次性加载的。而是通过点击加载更多的方式获取更多数据的。因此我们不能使用传统的方式爬数据。这里我们使用selenium+PhantomJS的方式爬取异步加载的电影:


#encoding: utf8

from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait

def crawle_movie(): # 初始化一个 webdriver 对象,使用的是 PhantomJS 浏览器 driver = webdriver.PhantomJS()

# 获取 douban 的电影
driver.get("https://movie.douban.com/")

# 电影列表
movie_list = []

# 点击获取更多电影
more_btn = driver.find_element_by_class_name('more')

while True:
    # 截取元素起始位置
    start_index = len(movie_list)

    # xpath 字符串。因为点击加载更多后,只需要获取新加载的数据,不需要获取之前的。所以给了一个 position
    xpath_str = "//a[@class='item'][position()>%d]" % start_index

    # 通过 xpath 获取的元素对象
    item_tags = driver.find_elements_by_xpath(xpath_str)

    print 'start_index:',start_index
    print '当前个数:',len(item_tags)

    # 遍历所有的元素对象
    for item_tag in item_tags:
        # 获取电影海报标签
        img_tag = item_tag.find_element_by_tag_name('img')
        # 获取电影海报的 src 属性对应的值
        cover = img_tag.get_attribute("src")
        # 获取电影海报对应的 alt,也即电影名
        title = img_tag.get_attribute("alt")
        # 通过 xpath 获取评分。注意:要通过 xpath 获取某个元素下的标签,那么应该前面加.
        rating = item_tag.find_element_by_xpath(".//p/strong").text
        movie = {
            'cover': cover,
            'title': title,
            'rating': rating
        }
        print u'电影名:' + title
        movie_list.append(movie)

    # 获取点击加载更多的按钮
    more_btn = driver.find_element_by_class_name('more')

    # 如果这个按钮有 style 这个属性,说明是已经达到最后一页了。不能再点击了。这时候就退出
    if more_btn.get_attribute('style'):
        break

    # 模拟加载更多按钮点击
    more_btn.click()

if name == ‘main’: crawle_movie()

如果想了解更多 Python 和爬虫相关知识,欢迎加群 482869582 一起学习交流!


Python中如何使用Selenium+PhantomJS加载ajax数据

1 回复

帖子标题:Python中如何使用Selenium+PhantomJS加载ajax数据

这个需求很常见,Selenium配合无头浏览器PhantomJS(虽然现在官方推荐用Chrome/Firefox的无头模式,但PhantomJS在某些老项目里还在用)确实能很好地处理动态加载的AJAX数据。

核心思路就是:用Selenium的WebDriver控制PhantomJS浏览器,等页面里的AJAX请求完成、数据渲染到DOM后再去抓取。

下面给你一个完整的示例代码:

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

# 设置PhantomJS路径(需要先下载phantomjs.exe并放在指定路径)
phantomjs_path = r'C:\path\to\phantomjs.exe'  # Windows示例
# 或者直接放环境变量里就不用指定路径了

# 创建PhantomJS浏览器实例
driver = webdriver.PhantomJS(executable_path=phantomjs_path)  # 如果phantomjs在环境变量中,可以省略executable_path

# 设置窗口大小(有时候页面响应式布局需要)
driver.set_window_size(1920, 1080)

# 访问目标页面
url = "https://example.com/ajax-page"  # 替换成你的目标URL
driver.get(url)

# 关键:等待AJAX数据加载完成
# 方法1:显式等待某个特定元素出现(推荐)
try:
    # 假设AJAX加载后会出现id为"ajax-content"的元素
    wait = WebDriverWait(driver, 10)  # 最多等10秒
    element = wait.until(
        EC.presence_of_element_located((By.ID, "ajax-content"))
    )
    print("AJAX内容已加载")
except Exception as e:
    print(f"等待元素超时: {e}")

# 方法2:简单粗暴的固定等待(不推荐,但有时候应急用)
# time.sleep(3)  # 强制等3秒

# 方法3:等待页面某个特定文本出现(比如"加载完成")
# wait.until(EC.text_to_be_present_in_element((By.TAG_NAME, "body"), "数据加载完成"))

# 现在可以获取渲染后的完整页面源码了
page_source = driver.page_source
print("页面源码长度:", len(page_source))

# 或者直接定位到AJAX数据所在的元素进行提取
ajax_data = driver.find_element(By.ID, "ajax-content").text
print("提取到的数据:", ajax_data[:100])  # 打印前100字符

# 如果需要点击按钮触发更多AJAX加载
# button = driver.find_element(By.CLASS_NAME, "load-more")
# button.click()
# 然后再等待新内容加载...

# 最后记得关闭浏览器
driver.quit()

几个关键点:

  1. 等待机制:一定要用WebDriverWait配合expected_conditions,比死等time.sleep()靠谱多了
  2. 元素定位:AJAX数据加载后,页面DOM结构通常会变化,要找准包含动态数据的那个容器元素
  3. 超时设置:根据网络情况和数据量调整等待时间,太短可能没加载完,太长浪费时间

替代方案提醒:PhantomJS已经停止维护了,现在更推荐用Chrome的无头模式:

from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--headless")  # 无头模式
driver = webdriver.Chrome(options=chrome_options)

用法和上面完全一样,性能更好,兼容性更强。

一句话总结:用显式等待确保AJAX加载完成再抓数据,别用time.sleep()硬等。

回到顶部