ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python爬虫实战:豆瓣电影与王者荣耀数据抓取完整方案

Python爬虫实战:豆瓣电影与王者荣耀数据抓取完整方案 1. 项目概述与核心价值最近在整理技术笔记翻到了几年前刚学Python爬虫时做的一个综合练习项目当时为了练手一口气爬了豆瓣电影Top250和王者荣耀全英雄信息还煞有介事地写了份实验报告。现在回头看这个项目虽然技术栈不新但作为爬虫入门到实战的过渡案例其涵盖的知识点非常经典从基础请求、数据解析到反爬应对、数据存储几乎把新手期该踩的坑都踩了一遍。今天就把这个老项目翻出来结合现在的技术环境重新梳理一遍分享给正在学习爬虫的朋友。无论你是想了解如何从豆瓣获取电影榜单还是想批量抓取王者荣耀的英雄资料来做个数据分析这篇内容都能给你提供一套可直接复现的完整方案。这个项目的核心价值在于“综合性”。它不像单一教程只讲一个网站而是通过两个风格迥异的目标豆瓣-静态页面、王者荣耀-动态数据接口让你在实践中对比不同场景下的爬虫策略。你会遇到简单的HTML解析也会碰到需要分析XHR请求的API接口会用到requests和BeautifulSoup这样的基础库也可能需要思考如何应对频率限制。最终你将得到两份结构化的数据一份是包含电影排名、名称、评分、评价人数的豆瓣榜单另一份是包含英雄名称、定位、技能、属性等详细资料的王者荣耀英雄库。这些数据无论是用于个人学习、课程作业还是作为更复杂数据分析项目的数据源都很有意义。2. 项目整体设计与思路拆解2.1 目标分析与技术选型这个项目包含两个独立但可类比的部分爬取豆瓣电影Top250和爬取王者荣耀全英雄信息。虽然目标不同但爬虫的核心流程是一致的发起请求 - 获取响应 - 解析数据 - 存储数据。我们的设计思路就是围绕这个流程为每个目标选择合适的工具和方法。对于豆瓣电影Top250这是一个经典的静态网页爬取案例。榜单页面https://movie.douban.com/top250是分页的每页25条共10页。页面结构清晰数据直接嵌入在HTML中。因此技术栈非常直接请求库requests。足够简单高效用于发送HTTP GET请求获取网页源代码。解析库BeautifulSoup。因为页面是标准的HTML使用BeautifulSoup配合CSS选择器或查找方法可以非常直观地定位和提取所需数据。核心挑战相对简单主要是构造分页URL和编写稳定的数据提取规则。可能需要处理一下豆瓣轻微的访问频率控制。对于王者荣耀全英雄信息情况则复杂一些。王者荣耀的官方网站或相关数据站其英雄列表和详情页的数据很可能通过JavaScript动态加载直接请求HTML可能拿不到英雄数据。因此我们需要换一种思路请求分析使用浏览器开发者工具的“网络”Network选项卡特别是筛选XHR/Fetch请求寻找真正返回英雄数据的API接口。这比解析渲染后的HTML更直接、更稳定。请求库依然是requests但可能需要更复杂的请求参数如headers特别是User-Agent、Referer来模拟浏览器。解析库由于API通常返回JSON格式的数据我们不再需要BeautifulSoup而是使用Python内置的json库来解析这比解析HTML简单得多。核心挑战找到正确的数据接口并构造合法的请求头以通过服务器的简单校验。数据存储两者可以统一。我们将提取的数据转化为Python的字典或列表然后使用pandas库方便地转换为DataFrame并保存为CSV或Excel文件便于后续查看和分析。也可以使用json模块直接保存为JSON文件。整体架构流程图文字描述豆瓣爬虫循环生成10个分页URL -requests.get()-BeautifulSoup()解析 - 提取单页25部电影信息 - 存入列表 - 保存为文件。王者爬虫分析找到英雄列表API -requests.get()带请求头 -json.loads()解析 - 获取所有英雄ID/名称 - 循环拼接英雄详情API - 获取每个英雄详细信息 - 存入列表 - 保存为文件。2.2 环境准备与工具清单工欲善其事必先利其器。以下是完成本项目需要准备的软件和Python库。我的开发环境是Windows 11 Python 3.9但以下步骤在各平台大同小异。1. 基础环境安装Python 3.7这是必须的。可以去Python官网下载安装包。安装时务必勾选“Add Python to PATH”。代码编辑器/IDE推荐使用VSCode或PyCharm Community Edition。VSCode轻量灵活PyCharm对Python支持更专业。我个人习惯用VSCode配置好Python插件后体验很好。浏览器开发者工具这是爬虫工程师的“眼睛”。Chrome或Edge的F12开发者工具是关键我们主要用它的“元素”Elements查看页面结构用“网络”Network分析数据请求。2. Python库安装打开你的终端CMD、PowerShell或终端使用pip命令安装以下库。建议先创建一个虚拟环境但为了简化我们直接进行全局安装。# 安装HTTP请求库 pip install requests # 安装HTML/XML解析库 pip install beautifulsoup4 # 安装数据处理库用于最后保存数据 pip install pandas # lxml是一个高效的解析器BeautifulSoup可以使用它来加速建议安装 pip install lxml安装完成后可以在Python交互环境中测试一下import requests, bs4, pandas as pd print(“所有库已就绪”)3. 辅助工具与意识培养请求头Headers生成有时候需要复制浏览器中的完整请求头。在开发者工具的“网络”选项卡中点击任意一个请求在右侧“标头”Headers部分找到“请求标头”可以直接复制User-Agent、Cookie等。一个小技巧requests库的session对象可以保持一些头部信息。延时设置出于道德和对目标网站服务器的尊重爬取时应在请求间添加随机延时避免高频访问。可以使用time.sleep()。异常处理网络请求不稳定解析规则可能因页面微调而失效。务必使用try...except包裹核心代码并记录日志。注意爬虫行为应始终遵守网站的robots.txt协议通常在网站根目录如https://www.douban.com/robots.txt并控制访问频率。本项目仅用于学习交流切勿用于商业用途或对服务器造成压力。3. 核心细节解析与实操要点3.1 豆瓣电影Top250爬取静态页面解析实战豆瓣Top250页面是学习爬虫的“Hello World”级项目但它能教会你处理分页、CSS选择器使用和数据结构化。第一步页面结构与URL规律分析打开https://movie.douban.com/top250查看页面源码右键-查看网页源代码。你会发现电影信息都在div class”item”…/div这个容器里。翻到第二页URL变成了https://movie.douban.com/top250?start25filter。规律很明显start参数控制起始条目每页25条。因此第i页从0开始的URL就是f”https://movie.douban.com/top250?start{i*25}filter”。第二步使用BeautifulSoup解析与数据提取我们需要从每个.item中提取电影排名、名称、评分、评价人数、引言等。这里用CSS选择器是最清晰的方式。from bs4 import BeautifulSoup import requests def parse_douban_page(html): “””解析一页豆瓣HTML返回电影信息列表””” soup BeautifulSoup(html, ‘lxml’) movie_list [] # 找到所有电影项目 items soup.select(‘div.item’) for item in items: # 排名在class”pic”的em标签里 rank item.select_one(‘em’).text # 标题在class”title”的第一个span里注意可能有中文名和英文名 title item.select_one(‘span.title’).text # 评分在class”rating_num”的span里 rating item.select_one(‘span.rating_num’).text # 评价人数在class”star”的span里最后一个span # 需要一些字符串处理来提取数字 star_span item.select_one(‘div.star’) if star_span: # 获取star下的所有文本然后分割 star_text star_span.get_text(stripTrue) # 通常格式如”9.7 2000000人评价”我们提取数字部分 import re rating_num_match re.search(r‘(\d)人评价’, star_text) rating_num rating_num_match.group(1) if rating_num_match else ‘0’ else: rating_num ‘0’ # 引言/短评在class”quote”的span里可能没有 quote_elem item.select_one(‘span.inq’) quote quote_elem.text if quote_elem else ‘’ movie_list.append({ ‘排名’: rank, ‘标题’: title, ‘评分’: rating, ‘评价人数’: rating_num, ‘引言’: quote }) return movie_list关键点与避坑指南选择器稳定性豆瓣的页面结构相对稳定但并非一成不变。如果某天代码跑不通了首先检查CSS类名是否变化。使用select_one比find结合复杂的属性更易读。文本清理get_text(stripTrue)可以移除多余空白。对于评价人数这种嵌套在文本中的数字正则表达式re是一个强大的工具。缺失项处理像quote引言不是每部电影都有所以要用if quote_elem:进行判断避免AttributeError。编码问题豆瓣使用UTF-8编码requests会自动处理一般没问题。如果遇到乱码可以检查response.encoding并手动设置。3.2 王者荣耀英雄信息爬取动态接口分析与JSON处理王者荣耀的数据通常通过后台接口获取这要求我们从“爬页面”转向“爬接口”。第一步寻找数据接口打开一个王者荣耀英雄资料网站例如王者荣耀官网或一些第三方资料站。打开浏览器开发者工具F12切换到“网络”Network选项卡。刷新页面在请求列表中筛选“XHR”或“Fetch”。仔细查看这些请求的URL和响应预览Preview。寻找包含herolist、hero、list等关键词且响应体是JSON格式的请求。这个过程可能需要一些耐心和猜测。举例我通过分析发现某个数据接口的URL模式类似于https://pvp.qq.com/web201605/js/herolist.json注意此URL为示例实际接口可能已变更请以你实际分析为准。这个接口直接返回了一个包含所有英雄基本信息的JSON数组。另一个常见模式可能有一个列表接口返回英雄ID然后详情接口模式为https://…/hero/{hero_id}.json。第二步分析接口请求与参数找到接口后查看它的“标头”Headers特别是Request Headers。你需要关注User-Agent告诉服务器你是什么浏览器。这是最基本的反爬措施必须携带一个常见的浏览器UA。Referer表示请求来自哪个页面。对于有些接口缺少正确的Referer会被拒绝。Cookie可能需要登录态才能获取数据但公开的英雄信息接口通常不需要。第三步编写爬取代码假设我们找到了英雄列表接口herolist.json它返回每个英雄的ename英雄ID、cname英雄名等。import requests import json import time import random def fetch_hero_list(): “””获取英雄列表””” url ‘https://pvp.qq.com/web201605/js/herolist.json’ # 示例URL需替换 headers { ‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36’, ‘Referer’: ‘https://pvp.qq.com/web201605/’ # 示例Referer } try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 检查请求是否成功 # 接口返回的可能是JSONP格式如herolistJsonCallback([…])需要处理 # 如果是纯JSON直接解析 hero_list resp.json() return hero_list except requests.exceptions.RequestException as e: print(f“请求英雄列表失败: {e}”) return [] except json.JSONDecodeError: # 尝试处理JSONP text resp.text # 简单去除JSONP包装实际情况可能更复杂 if text.startswith(‘herolistJsonCallback’): json_str text[text.find(‘[‘): text.rfind(‘]’)1] return json.loads(json_str) return [] def fetch_hero_detail(hero_id, hero_name): “””根据英雄ID获取英雄详情””” # 详情页接口需要根据实际分析得到 detail_url f‘https://pvp.qq.com/web201605/js/herodetail/{hero_id}.json’ # 示例 headers {…} # 同上可能需要不同的Referer try: resp requests.get(detail_url, headersheaders, timeout10) resp.raise_for_status() detail_data resp.json() # 提取我们需要的信息 return { ‘英雄ID’: hero_id, ‘英雄名称’: hero_name, ‘定位’: ‘、’.join(detail_data.get(‘occupation’, [])), # 可能是个列表 ‘生存能力’: detail_data.get(‘survival’, ‘’), ‘攻击伤害’: detail_data.get(‘attack’, ‘’), ‘技能效果’: detail_data.get(‘skill’, ‘’), ‘上手难度’: detail_data.get(‘difficulty’, ‘’), ‘技能介绍’: process_skills(detail_data.get(‘skills’, [])), # 自定义处理函数 } except Exception as e: print(f“获取英雄 {hero_name}({hero_id}) 详情失败: {e}”) return None finally: # 礼貌性延时避免请求过快 time.sleep(random.uniform(0.5, 1.5))关键点与避坑指南接口寻找是关键这是动态网站爬虫最难也最重要的一步。多试试不同的筛选条件JS、XHR关注返回数据量大的请求。如果官网接口难找可以搜索“王者荣耀 英雄数据 API”有些社区或开发者会整理公开接口但要注意其可用性和合法性。处理JSONP有些老式接口会使用JSONP即用JavaScript函数包裹JSON数据。你需要从响应文本中剥离掉函数名和括号提取出纯JSON字符串。正则表达式或简单的字符串切片可以解决。请求头模拟务必带上合理的User-Agent和Referer。可以直接从浏览器开发者工具里复制。异常处理与延时网络请求和JSON解析都可能出错必须用try…except捕获。在循环请求详情页时time.sleep(random.uniform(a, b))是必备的既能防止IP被封也是对服务器的尊重。数据字段不统一不同接口返回的字段名和结构可能不同。你需要仔细查看JSON响应适配你的解析代码。detail_data.get(‘key’, default)的方式可以避免KeyError。4. 实操过程与核心环节实现4.1 豆瓣爬虫完整实现与数据存储将上面的解析函数整合进一个完整的爬虫流程并加入分页循环和存储功能。import requests from bs4 import BeautifulSoup import pandas as pd import time import random def crawl_douban_top250(): “””爬取豆瓣Top250所有电影””” base_url “https://movie.douban.com/top250” all_movies [] headers { ‘User-Agent’: ‘Mozilla/5.0 … Safari/537.36’ } for page in range(0, 10): # 0-9页 start page * 25 url f“{base_url}?start{start}filter” print(f“正在爬取第 {page1} 页: {url}”) try: resp requests.get(url, headersheaders, timeout15) resp.raise_for_status() # 豆瓣有时会用一些简单的反爬检查一下状态码和内容 if resp.status_code ! 200: print(f“第 {page1} 页请求异常状态码: {resp.status_code}”) break # 检查页面是否包含关键元素防止被重定向到登录页等 if “登录豆瓣” in resp.text: print(“可能触发了反爬需要检查Cookie或访问频率。”) break movies parse_douban_page(resp.text) # 使用前面定义的解析函数 all_movies.extend(movies) print(f“第 {page1} 页爬取完成共 {len(movies)} 部电影。”) except requests.exceptions.RequestException as e: print(f“爬取第 {page1} 页时发生网络错误: {e}”) # 可以在这里加入重试逻辑 break except Exception as e: print(f“解析第 {page1} 页时发生未知错误: {e}”) break # 随机延时模拟人类浏览 time.sleep(random.uniform(1, 3)) # 存储数据 if all_movies: df pd.DataFrame(all_movies) # 调整列顺序 df df[[‘排名’, ‘标题’, ‘评分’, ‘评价人数’, ‘引言’]] # 保存为CSV df.to_csv(‘douban_top250.csv’, indexFalse, encoding‘utf_8_sig’) # utf_8_sig解决Excel打开乱码 # 保存为Excel # df.to_excel(‘douban_top250.xlsx’, indexFalse) print(f“所有数据爬取完成共 {len(all_movies)} 条记录已保存至 douban_top250.csv”) return df else: print(“未爬取到任何数据。”) return None if __name__ ‘__main__’: crawl_douban_top250()存储格式说明这里选择了CSV格式因为它通用、轻量可以用Excel、文本编辑器或pandas直接打开。encoding‘utf_8_sig’是为了让生成的CSV文件在Windows系统下的Excel中打开时中文字符能正常显示不会变成乱码。如果你需要更复杂的格式如多个工作表可以使用to_excel方法。4.2 王者荣耀爬虫完整实现与数据聚合王者荣耀的爬虫需要先获取列表再遍历列表获取详情是一个典型的两步爬取。import requests import json import pandas as pd import time import random def crawl_king_of_glory(): “””爬取王者荣耀全英雄信息””” print(“开始爬取王者荣耀英雄列表…”) hero_list fetch_hero_list() # 使用前面定义的函数 if not hero_list: print(“获取英雄列表失败程序退出。”) return print(f“共发现 {len(hero_list)} 个英雄。”) all_hero_details [] for idx, hero in enumerate(hero_list): hero_id hero.get(‘ename’) hero_name hero.get(‘cname’) if not hero_id: continue print(f“[{idx1}/{len(hero_list)}] 正在爬取英雄: {hero_name} (ID: {hero_id})”) detail fetch_hero_detail(hero_id, hero_name) # 使用前面定义的函数 if detail: all_hero_details.append(detail) else: print(f“英雄 {hero_name} 详情爬取失败已跳过。”) # 进度提示与延时 if (idx 1) % 5 0: print(f“已处理 {idx1} 个英雄…”) # 存储数据 if all_hero_details: df pd.DataFrame(all_hero_details) # 你可以根据需要调整列的顺序 output_columns [‘英雄ID’, ‘英雄名称’, ‘定位’, ‘生存能力’, ‘攻击伤害’, ‘技能效果’, ‘上手难度’, ‘技能介绍’] # 确保DataFrame包含这些列不存在的列会被忽略或填充NaN df df.reindex(columnsoutput_columns) df.to_csv(‘king_of_glory_heroes.csv’, indexFalse, encoding‘utf_8_sig’) print(f“英雄详情爬取完成共 {len(all_hero_details)} 条记录已保存至 king_of_glory_heroes.csv”) return df else: print(“未成功爬取到任何英雄详情。”) return None # 辅助函数处理技能列表将其转换为可读的字符串 def process_skills(skills_list): if not skills_list: return ‘’ skill_texts [] for skill in skills_list: name skill.get(‘name’, ‘未知技能’) desc skill.get(‘description’, ‘无描述’) # 简单格式化可以更复杂 skill_texts.append(f“{name}: {desc[:50]}…” if len(desc) 50 else f“{name}: {desc}”) return ‘ | ‘.join(skill_texts) if __name__ ‘__main__’: crawl_king_of_glory()数据聚合要点这个脚本的核心是crawl_king_of_glory函数。它先获取总列表然后遍历每个英雄ID去获取详情。在循环中加入了进度打印和随机延时使得运行过程更友好也降低了被封风险。process_skills是一个示例函数展示了如何将嵌套的JSON技能数据通常是列表套字典扁平化成一段易于存储和阅读的文本。在实际操作中你可能需要根据接口返回的实际数据结构来调整这个函数。5. 常见问题与排查技巧实录爬虫代码很少能一次写对永远跑通。在实际操作中你会遇到各种各样的问题。下面是我在运行这两个爬虫时遇到过的一些典型问题及解决方法希望能帮你少走弯路。5.1 请求被拒绝或返回异常数据问题现象requests.get()返回的状态码是403、404或者返回的HTML内容很短包含“访问过于频繁”、“请验证”等字样。可能原因与排查缺少或错误的请求头这是最常见的原因。服务器通过User-Agent识别爬虫。解决务必添加一个常见的浏览器User-Agent。对于某些网站如豆瓣可能还需要Referer、Accept-Language等。直接从浏览器开发者工具里复制整个Request Headers有时很有效。IP被暂时限制短时间内发送过多请求。解决这是必须遵守的规则。在循环请求中务必加入time.sleep(random.uniform(2, 5))这样的随机延时。对于豆瓣这类网站间隔2-5秒是比较安全的。可以考虑使用random来让间隔时间不规律。需要Cookie或登录态有些页面如豆瓣查看更多时可能需要登录后的Cookie。解决先手动在浏览器登录然后从开发者工具中复制Cookie字段添加到请求头。注意Cookie会过期。更复杂的情况需要模拟登录流程涉及session、post请求和表单处理这属于中级爬虫内容。目标URL已变更或接口失效特别是对于王者荣耀的接口腾讯可能会调整API地址。解决重新使用开发者工具分析网络请求找到新的数据接口URL。这是动态爬虫的常态。5.2 解析失败提取不到数据问题现象soup.select()返回空列表或者resp.json()抛出JSONDecodeError。可能原因与排查页面结构已更新网站的HTML结构或CSS类名变了。解决重新检查页面元素。使用soup.prettify()打印一部分HTML出来或者用浏览器的“检查”功能重新确认目标数据所在的标签和其属性。不要写死解析逻辑考虑使用更通用的选择方式如通过多个标签层级定位。数据是JavaScript动态加载的你以为爬的是HTML但数据是JS后来渲染的。解决这是王者荣耀爬虫部分的核心。必须去“网络”选项卡找真正的数据接口XHR/Fetch而不是解析初始的HTML文档。JSONP格式问题接口返回的是JSONP不是纯JSON。解决如前面代码所示需要先截取响应文本中(和)之间的部分或者用正则提取JSON字符串。编码问题虽然不多见但有些页面可能不是UTF-8。解决检查resp.encoding如果不对可以手动设置例如resp.encoding ‘gbk’。5.3 数据存储乱码或格式错误问题现象CSV文件用Excel打开中文是乱码或者用文本编辑器打开发现格式不对。解决Excel乱码这是Windows下Excel的“老毛病”。在调用to_csv时指定encoding‘utf_8_sig’。这个编码会在文件开头添加一个BOM字节顺序标记Excel就能正确识别UTF-8了。字段包含逗号或换行符CSV默认用逗号分隔如果数据本身有逗号会导致列错位。解决to_csv方法默认会用双引号包裹包含特殊字符的字段。确保你的数据是干净的或者考虑使用sep‘\t’制表符分隔保存为TSV文件。想保存更多格式除了CSVpandas可以轻松保存为Excel.xlsx、JSON.json甚至数据库。选择最适合你后续处理需求的格式。5.4 脚本运行不稳定中途崩溃问题现象爬到一半因为网络超时、解析错误等原因停止。解决健壮性编程。全面使用try-except将网络请求、数据解析、文件操作等可能出错的代码块都用try…except包裹并在except中记录错误日志打印到屏幕或写入文件而不是让整个程序崩溃。设置超时requests.get(url, timeout10)避免因为某个请求卡住而无限等待。加入重试机制对于网络请求失败如超时、连接错误可以设计一个重试循环例如重试3次。可以使用tenacity库也可以自己写一个简单的循环。分段保存如果爬取数据量很大不要等到全部爬完再保存。可以每爬取10个或20个条目就追加写入一次文件。这样即使程序中途出错也已经保存了部分成果。5.5 关于“实验报告”的额外建议既然标题提到了“实验报告”如果你需要将这个过程整理成一份报告除了代码和结果还应该包含以下部分实验目的掌握静态网页和动态接口两种数据爬取方法。实验环境列出你的Python版本、第三方库及版本号pip freeze可以查看。实验原理与分析阐述requests、BeautifulSoup、开发者工具分析网络请求的工作原理。实验步骤将上面的代码实现过程分步骤描述。实验结果与分析展示爬取到的数据片段用表格形式分析数据质量讨论遇到的问题和解决方案。实验总结总结两种爬虫方式的异同、各自的适用场景以及本次实践的收获。最后爬虫技术是一把双刃剑。在学习和练习过程中请始终牢记尊重robots.txt查看目标网站的robots.txt文件了解哪些目录是允许爬取的。控制访问频率这是最重要的道德和法律底线。不要对目标服务器造成负担。明确数据用途爬取的数据仅用于个人学习、研究或公益目的切勿用于商业用途或侵犯他人权益。遵守网站条款有些网站明确禁止爬虫行为。
返回列表