1. 项目背景与需求分析
最近在技术社区看到不少同行讨论如何用Python实现影视资源爬取,正好手头有个实际需求——需要定期获取某视频网站的更新内容。这个案例特别适合用来演示Python爬虫的实战技巧,因为影视类网站通常会有反爬机制,但又不像金融或政务网站那么严格,属于"练手难度适中"的类型。
我选择的目标网站是一个移动端优先的视频平台(根据热词提示"reminder: this website only supports mobile device access"),这类网站在爬取时需要特别注意User-Agent和请求头的处理。从技术角度看,我们需要解决几个核心问题:
- 如何绕过移动端限制
- 如何解析动态加载的内容
- 如何高效提取影视链接
- 如何应对可能的反爬策略
2. 环境准备与工具选型
2.1 Python环境配置
推荐使用conda管理环境(热词中多次出现conda和py环境配置):
bash复制conda create -n video_spider python=3.8
conda activate video_spider
关键库安装:
bash复制pip install requests bs4 selenium webdriver-manager
选择这些库的考虑:
- requests:比urllib更人性化的HTTP库
- bs4:HTML解析神器
- selenium:应对动态渲染页面
- webdriver-manager:自动管理浏览器驱动
2.2 移动端访问模拟
由于目标网站强制移动端访问,我们需要精心配置请求头:
python复制headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2'
}
提示:User-Agent字符串可以从真实手机的浏览器开发者工具中获取,比用模拟器生成的更可靠
3. 页面分析与数据提取
3.1 静态页面结构解析
首先尝试用requests+BeautifulSoup组合:
python复制import requests
from bs4 import BeautifulSoup
url = "https://nup13.top/vod/list.html?type_id=1035" # 来自热词中的示例URL
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# 查找影视条目
items = soup.select('.video-item') # 需要根据实际页面调整选择器
for item in items:
title = item.select_one('.title').text
link = item.select_one('a')['href']
print(f"{title}: {link}")
常见问题处理:
- 如果返回空列表,可能是选择器不对或内容动态加载
- 注意相对路径转绝对路径:
urllib.parse.urljoin(base_url, relative_path)
3.2 动态内容处理方案
当发现目标数据是通过AJAX加载时,可以:
- 查找真实的API接口(通过浏览器开发者工具)
- 使用selenium模拟浏览器
方案二示例:
python复制from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--headless") # 无头模式
chrome_options.add_argument("user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1")
driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options)
driver.get(url)
# 等待动态内容加载
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".video-item"))
)
# 提取数据...
finally:
driver.quit()
4. 反爬对抗策略
4.1 常见反爬手段应对
根据热词中出现的"py混淆"提示,说明目标网站可能有JS混淆:
-
IP限制:使用代理池
python复制proxies = { 'http': 'http://proxy_ip:port', 'https': 'http://proxy_ip:port' } response = requests.get(url, headers=headers, proxies=proxies) -
请求频率限制:添加随机延迟
python复制import random, time time.sleep(random.uniform(1, 3)) -
Cookie验证:维持会话
python复制
session = requests.Session() session.headers.update(headers) response = session.get(url)
4.2 高级技巧:处理加密参数
某些网站会在请求中添加时间戳或加密参数:
python复制import hashlib
import time
def generate_sign(params):
secret = 'website_secret_key' # 需要通过逆向分析获取
timestamp = str(int(time.time()))
raw = f"{params}{timestamp}{secret}"
return hashlib.md5(raw.encode()).hexdigest()
5. 数据存储与后续处理
5.1 结构化存储方案
建议使用SQLite或MySQL存储结果:
python复制import sqlite3
conn = sqlite3.connect('videos.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS videos
(id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
url TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
# 插入数据
c.execute("INSERT INTO videos (title, url) VALUES (?, ?)", (title, url))
conn.commit()
5.2 可执行文件打包
根据热词需求,可以使用PyInstaller打包(注意处理资源文件):
bash复制pyinstaller --onefile --add-data 'videos.db;.' spider.py
对于更复杂的打包需求(如热词中提到的多个.py文件打包),建议:
bash复制pyinstaller --onefile --add-data 'videos.db;.' --hidden-import=module_name main.py
6. 实战经验与避坑指南
-
User-Agent轮换:准备多个移动端UA轮流使用,避免单一UA被识别
-
超时处理:所有网络请求必须设置超时
python复制try: response = requests.get(url, headers=headers, timeout=(3.05, 27)) except requests.exceptions.Timeout: print(f"Timeout occurred for {url}") -
异常重试:实现自动重试机制
python复制from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) def fetch_url(url): return requests.get(url, headers=headers) -
日志记录:详细记录爬取过程
python复制import logging logging.basicConfig( filename='spider.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) -
增量爬取:通过记录最后爬取时间避免重复
python复制last_crawl_time = get_last_crawl_time() # 从数据库或文件读取 if item['update_time'] > last_crawl_time: process_new_item(item)
这个案例中最容易出问题的环节是动态内容加载和反爬措施。我在实际测试中发现,目标网站会检测鼠标移动轨迹,纯headless模式容易被识别。解决方案是在selenium中添加随机鼠标移动:
python复制from selenium.webdriver.common.action_chains import ActionChains
import random
def random_mouse_move(driver):
action = ActionChains(driver)
for _ in range(5):
x = random.randint(0, 300)
y = random.randint(0, 300)
action.move_by_offset(x, y).perform()
