影刀RPA考试实战:用Python绕过网站反爬,把电影票房数据自动存进MySQL数据库
影刀RPA实战:Python自动化抓取票房数据与MySQL存储全解析
当我们需要从电影票房网站抓取数据并存入数据库时,传统手动操作既耗时又容易出错。本文将带你深入探索如何利用影刀RPA结合Python技术栈,构建一个稳定可靠的自动化数据采集系统。这个方案不仅适用于影刀RPA认证考试准备,也能直接应用于实际业务场景中的数据采集需求。
1. 环境准备与基础配置
在开始编写自动化脚本前,我们需要搭建好开发环境并了解核心工具链。影刀RPA提供了Python编码环境,让我们能够灵活地处理各种复杂的数据采集任务。
首先确保已安装以下Python库:
pip install pymysql xbot
影刀RPA的xbot包封装了浏览器自动化、数据表格处理等常用功能,而pymysql则是Python连接MySQL数据库的标准库。对于这个项目,我们还需要处理网页解析,影刀内置的web模块已经足够强大。
提示:在影刀RPA环境中,部分库可能已预装,建议先检查现有环境再决定是否需要额外安装
数据库连接配置是项目的基础,我们需要准备以下信息:
| 配置项 | 示例值 | 说明 |
|---|---|---|
| 主机地址 | 43.143.30.32 | 数据库服务器IP |
| 端口 | 3306 | MySQL默认端口 |
| 用户名 | yingdao | 数据库用户名 |
| 密码 | 9527 | 数据库密码 |
| 数据库名 | ydtest | 目标数据库名称 |
| 表名 | movies | 存储电影数据的表名 |
2. 反爬策略与请求控制
现代网站普遍部署了反爬虫机制,直接快速连续请求很容易触发防护系统。我们需要设计合理的请求策略来模拟人类操作行为。
2.1 随机延迟实现
在关键操作之间插入随机等待时间是绕过基础反爬的有效方法:
from xbot import sleep
import random
def random_sleep(min=1, max=3):
"""在min和max秒之间随机等待"""
sleep(random.uniform(min, max))
这个简单的随机延迟函数可以在每次页面跳转或数据提取后调用,使请求间隔变得不规则。实际应用中,建议:
- 页面跳转间使用较长延迟(2-5秒)
- 同页面内元素提取使用较短延迟(0.5-1.5秒)
- 根据目标网站响应速度调整参数
2.2 请求头与行为模拟
除了时间控制,请求头的合理设置也能降低被识别为机器人的概率。影刀RPA的web模块已经处理了基础的头信息,但我们可以进一步定制:
web_page = xbot.web.create(
url="https://example.com",
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'zh-CN,zh;q=0.9'
}
)
3. 数据提取与XPath技巧
电影数据通常分布在网页的不同位置,需要精心设计的XPath表达式来准确定位。影刀RPA支持标准的XPath语法,我们可以利用它提取复杂结构的数据。
3.1 基础元素提取
电影名称、上映年份等基础信息通常有固定的位置:
# 电影名称
name = web_dg.find_by_xpath('//h1[@class="movie-title"]').get_text()
# 上映年份
year = web_dg.find_by_xpath('//span[contains(@class,"year")]').get_text()
3.2 复杂数据提取:导演信息
导演信息可能涉及多个元素,特别是当电影有联合导演时:
def get_directors(web_dg):
"""获取导演信息,多个导演用英文逗号分隔"""
directors = []
try:
elements = web_dg.find_all_by_xpath('//dt[text()="导演"]/following-sibling::dd')
for element in elements:
if element and element.get_text():
directors.append(element.get_text().strip())
except Exception as e:
print(f"获取导演信息时发生错误: {e}")
return ', '.join(directors)
这个函数处理了以下情况:
- 定位"导演"标签后的所有dd元素
- 过滤空内容
- 将多个导演合并为逗号分隔的字符串
- 包含异常处理防止程序中断
3.3 票房数据转换
票房数据通常带有单位(万/亿),需要统一转换为数值:
def convert_box_office(value):
"""转换票房数据为统一单位(万)"""
if not value:
return 0
value = str(value).strip()
if '亿' in value:
return float(value.replace('亿', '')) * 10000
elif '万' in value:
return float(value.replace('万', ''))
else:
return float(value)
4. 数据清洗与格式化
原始数据往往不符合数据库字段要求,需要进行清洗和转换。这部分工作虽然繁琐,但对保证数据质量至关重要。
4.1 数据类型转换
数据库字段有严格的类型要求,我们需要确保数据匹配:
def format_data(raw_data):
"""格式化原始数据为数据库兼容格式"""
name, year, area, poster, director, box_office, submitter = raw_data
# 处理年份
try:
year = int(year) if year else 0
except ValueError:
year = 0
# 处理票房
box_office = convert_box_office(box_office)
# 处理导演列表
director = director if director else '未知'
return (name, year, area, poster, director, box_office, submitter)
4.2 空值处理策略
不同字段的空值处理方式可能不同:
| 字段 | 空值处理方式 | 说明 |
|---|---|---|
| 电影名称 | 跳过该记录 | 关键字段不能为空 |
| 上映年份 | 设为0 | 数值字段需要默认值 |
| 导演 | 设为"未知" | 字符串字段需要占位符 |
| 票房 | 设为0 | 数值计算需要有效默认值 |
5. 数据库操作与错误处理
数据库交互是自动化流程中最容易出错的环节,需要完善的错误处理机制。
5.1 连接管理与重试
数据库连接应该具备重试机制:
def create_db_connection(max_retries=3):
"""创建数据库连接,带重试机制"""
retry_count = 0
while retry_count < max_retries:
try:
conn = pymysql.connect(
host="43.143.30.32",
port=3306,
user="yingdao",
password="9527",
database="ydtest",
charset='utf8'
)
return conn
except pymysql.Error as e:
print(f"数据库连接失败: {e}")
retry_count += 1
sleep(5 * retry_count) # 指数退避
raise Exception("无法建立数据库连接")
5.2 批量插入与事务
为了提高效率,可以考虑批量插入数据:
def batch_insert_data(conn, data_list):
"""批量插入数据到数据库"""
sql = """INSERT INTO movies
(电影名称, 上映年份, 制片地区, 海报链接, 导演, 票房, 提交人)
VALUES (%s, %s, %s, %s, %s, %s, %s)"""
try:
with conn.cursor() as cursor:
cursor.executemany(sql, data_list)
conn.commit()
return cursor.rowcount
except pymysql.Error as e:
conn.rollback()
print(f"数据库插入失败: {e}")
return 0
5.3 常见错误排查
在实际运行中可能会遇到以下典型问题:
- 连接超时:检查网络状况,增加连接超时参数
- 编码问题:确保数据库和连接都使用UTF-8编码
- 数据类型不匹配:仔细检查每个字段的数据类型
- 权限不足:确认数据库用户有写入权限
6. 完整流程整合
将各个模块整合为完整的自动化流程:
def main(submitter):
"""主函数,执行完整的数据采集流程"""
conn = None
try:
# 初始化数据库连接
conn = create_db_connection()
# 打开电影列表页
list_page = xbot.web.create(url="https://www.endata.com.cn/BoxOffice/BO/History/Movie/Alltimedomestic.html")
random_sleep()
# 获取所有电影链接
movie_links = list_page.find_all_by_xpath('//tbody/tr/td/a')
if not movie_links:
print("未找到电影链接")
return
# 准备批量插入的数据
batch_data = []
for link in movie_links:
movie_url = 'https://www.endata.com.cn' + link.get_attribute('href')
detail_page = xbot.web.create(url=movie_url)
random_sleep()
# 提取各项数据
name = detail_page.find_by_xpath('//h1').get_text()
year = detail_page.find_by_xpath('//span[@class="year"]').get_text()
area = detail_page.find_by_xpath('//dt[text()="制片地区"]/following-sibling::dd').get_text()
poster = detail_page.find_by_xpath('//div[@class="poster"]/img').get_attribute('src')
director = get_directors(detail_page)
box_office = detail_page.find_by_xpath('//dt[text()="票房"]/following-sibling::dd').get_text()
# 格式化数据
formatted = format_data((name, year, area, poster, director, box_office, submitter))
batch_data.append(formatted)
# 每10条数据批量插入一次
if len(batch_data) >= 10:
inserted = batch_insert_data(conn, batch_data)
print(f"成功插入{inserted}条记录")
batch_data = []
detail_page.close()
random_sleep()
# 插入剩余数据
if batch_data:
inserted = batch_insert_data(conn, batch_data)
print(f"成功插入{inserted}条记录")
except Exception as e:
print(f"程序运行出错: {e}")
finally:
if conn:
conn.close()
7. 性能优化与扩展思路
基础功能实现后,我们可以考虑进一步优化和扩展系统能力。
7.1 断点续爬实现
长时间运行的爬虫可能会中断,记录进度很重要:
# 保存进度到文件
def save_progress(last_processed):
with open('progress.txt', 'w') as f:
f.write(str(last_processed))
# 读取进度
def load_progress():
try:
with open('progress.txt', 'r') as f:
return int(f.read())
except:
return 0
7.2 分布式扩展
当数据量很大时,可以考虑分布式采集:
- 将电影列表分片处理
- 使用消息队列分配任务
- 多个worker并行采集
- 集中存储结果
7.3 监控与报警
生产环境中的自动化任务需要监控:
- 记录成功/失败次数
- 监控运行时间
- 异常情况邮件通知
- 定期生成运行报告
在实际项目中,我发现最耗时的部分往往是异常处理和日志记录,但这部分工作对长期维护至关重要。建议在开发初期就建立完善的日志系统,记录足够多的上下文信息,这样在出现问题时能够快速定位原因。
更多推荐


所有评论(0)