兄弟们,是不是经常遇到这种情况:当你哼着小曲用requests+BeautifulSoup写爬虫时,网页源码里居然搜不到你要的数据?别怀疑人生,这不是你代码写错了,而是你遇到了会“变脸”的动态网页!今天咱们就掏出专业治各种不服的爬虫黄金搭档——Selenium+PhantomJS。
一、为什么你的爬虫突然变“瞎子”?
前两天我徒弟小张试图抓取某电商网站促销信息,信誓旦旦写了段requests代码,结果返回的html里只有“正在加载中...”的鬼打墙提示。这就是典型的JavaScript动态渲染问题——很多现代网站就像变形金刚,初次访问只给个空壳,真正的内容要等JavaScript执行后才组装。
传统爬虫的三大死穴:
- JS渲染的内容直接失踪
- 登录状态无法保持
- 复杂交互动作直接懵逼
而Selenium这个神器,本质上是个远程遥控器,能模拟真实用户操作浏览器。配上无头浏览器PhantomJS(无需显示界面的浏览器),完美实现“看不见的伸手党”。
二、环境搭建:5分钟搞定神兵利器
# 安装必备包,在终端输入:
pip install selenium
# PhantomJS需要去官网下载exe文件放至脚本目录
避坑指南:2023年后PhantomJS逐渐被Chrome无头模式替代,但考虑到某些老项目还在用,而且资源占用更小,咱们还是先掌握这个经典组合。新手建议直接使用,老鸟可以无缝切换Chrome driver。
三、实战:手把手教你抓取某宝搜索结果
假设我们要监控某宝上“机械键盘”的价格变动,直接上硬核代码:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time, csv
class TaoBaoSpider:
def __init__(self):
# 启动幽灵司机PhantomJS
self.driver = webdriver.PhantomJS()
self.driver.implicitly_wait(10) # 隐式等待,对付网络延迟
def search_products(self, keyword):
print("正在启动隐身购物车...")
self.driver.get("https://www.taobao.com")
# 定位搜索框的XPath(F12开发者工具直接复制)
search_box = self.driver.find_element(By.XPATH, '//input[@id="q"]')
search_box.send_keys(keyword) # 输入关键词
# 点击搜索按钮
search_btn = self.driver.find_element(By.XPATH, '//button[@class="btn-search"]')
search_btn.click()
# 关键!等待结果加载
time.sleep(3)
# 获取商品列表
products = self.driver.find_elements(By.XPATH, '//div[@class="item J_MouserOnverReq"]')
print(f"抓到{len(products)}个商品")
data = []
for product in products:
try:
title = product.find_element(By.XPATH, './/div[@class="title"]/a').text
price = product.find_element(By.XPATH, './/div[@class="price"]/strong').text
sales = product.find_element(By.XPATH, './/div[@class="deal-cnt"]').text
data.append({
'title': title.strip(),
'price': price,
'sales': sales
})
except Exception as e:
print("解析某个商品时出错:", e)
continue
return data
def save_to_csv(self, data, filename):
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['title', 'price', 'sales'])
writer.writeheader()
writer.writerows(data)
print(f"数据已保存到{filename}")
def close(self):
self.driver.quit()
if __name__ == "__main__":
spider = TaoBaoSpider()
try:
results = spider.search_products("机械键盘")
spider.save_to_csv(results, "机械键盘搜索结果.csv")
finally:
spider.close()
代码逐行解读:
implicitly_wait(10)设置全局超时,比死等更智能- XPath定位比CSS选择器更灵活,右键复制即可
time.sleep(3)是给JS渲染留出时间,可根据网络调整- try-except包裹单个商品解析,避免一个商品出错导致全军覆没
四、应对反爬虫的骚操作
别以为用了无头浏览器就高枕无忧,网站还有这些防御手段:
1. 检测WebDriver属性
# 在启动时添加反检测参数
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
2. 随机延时伪装人类
import random
time.sleep(random.uniform(1, 3)) # 随机等待1-3秒
3. 模拟鼠标移动轨迹
from selenium.webdriver import ActionChains
action = ActionChains(driver)
action.move_to_element(element).perform()
五、PhantomJS与Chrome无头模式对比
|
特性 |
PhantomJS |
Chrome无头模式 |
|
内存占用 |
约100MB |
约300MB |
|
速度 |
较快 |
中等 |
|
更新维护 |
已停止 |
持续更新 |
|
兼容性 |
较好 |
完美兼容 |
2024年建议:新项目直接上Chrome无头模式,老项目维护继续用PhantomJS。
六、常见翻车现场及救援方案
翻车1:元素定位失败
- 症状:NoSuchElementException满天飞
- 解药:换用更稳定的定位方式,如改用ID或name
翻车2:弹窗打断流程
- 症状:突然跳出登录框
- 解药:启动时添加参数禁止弹窗
options.add_argument('--disable-popup-blocking')
翻车3:被网站封IP
- 症状:连续返回403错误
- 解药:配置IP代理池,每N个请求换IP
七、进阶技巧:让爬虫更“拟人”
想要爬虫活得久,就得让它演得像个人:
- 随机滚动页面:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") - 随机切换UserAgent
- 工作日白天多休息,深夜周末多干活
- 模拟不同地区的访问IP
记得去年我用这套方法持续监控了某平台3个月的价格数据,从没失手。关键就是要把握好“贪婪”与“克制”的平衡。
八、总结
Selenium+PhantomJS这对黄金组合,相当于给爬虫装上了机械臂和隐形斗篷。虽然速度比直接请求慢些,但成功率高啊!特别适合:
- 需要登录的网站
- JS重度依赖的SPA应用
- 需要模拟点击、滚动等操作的场景
记住爬虫界的至理名言:你能看到的内容,理论上都能抓取。下次遇到动态网页别再头铁硬刚了,把这篇教程甩给它看!
1688

被折叠的 条评论
为什么被折叠?



