手把手教你用Xpath爬取豆瓣电影Top250:从分析页面结构到数据存储的完整流程
零基础实战用Xpath精准抓取豆瓣电影Top250全流程指南豆瓣电影Top250榜单作为互联网上最具公信力的电影评分集合之一包含了影史经典与当代佳作。对于数据分析爱好者而言这个列表不仅是观影指南更是绝佳的数据分析素材。本文将带你从零开始使用Python中最高效的lxml库配合Xpath语法完整实现榜单数据的自动化采集。1. 环境准备与目标分析在开始编写爬虫之前我们需要先搭建好开发环境。推荐使用Python 3.8版本这是目前最稳定的Python发行版。关键依赖库包括pip install lxml requests pandaslxml高性能HTML/XML解析库支持Xpath 1.0语法requests简洁优雅的HTTP请求库pandas数据处理的瑞士军刀用于最终的数据存储提示为避免对目标网站造成过大访问压力建议在代码中添加适当的延时如3-5秒/页并设置合理的User-Agent头部。豆瓣Top250页面结构非常规整每页展示25部电影共10页。我们需要提取的核心数据字段包括字段名Xpath定位特征数据类型电影名称class为title的span标签字符串评分class为rating_num的span标签浮点数评价人数包含人评价文本的div整数经典台词class为quote的span标签字符串详情链接a标签的href属性URL2. 页面结构深度解析打开豆瓣电影Top250页面https://movie.douban.com/top250右键选择检查进入开发者工具。通过元素检查器可以发现每部电影信息都包裹在一个class为item的div中这将成为我们定位的基准点。关键DOM结构如下ol classgrid_view li div classitem div classinfo div classhd a href... span classtitle电影名称/span /a /div div classbd div classstar span classrating_num9.6/span span1234567人评价/span /div p classquote span classinq经典台词/span /p /div /div /div /li !-- 其他24部电影结构相同 -- /ol基于此结构我们可以设计出精准的Xpath表达式电影名称//div[classitem]//span[classtitle][1]/text()评分//div[classitem]//span[classrating_num]/text()评价人数//div[classitem]//div[classstar]/span[last()]/text()经典台词//div[classitem]//span[classinq]/text()详情链接//div[classitem]//div[classhd]/a/href注意电影名称有两个span元素中文名和原名我们通常只需要中文名因此添加了[1]索引。3. 核心爬取代码实现下面我们分步骤实现完整的爬取逻辑。首先是基础请求函数import requests from lxml import html import time import pandas as pd HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } def get_page(url): 获取页面HTML内容 try: resp requests.get(url, headersHEADERS) resp.raise_for_status() return resp.text except requests.exceptions.RequestException as e: print(f请求失败: {e}) return None接下来是解析单页电影数据的核心函数def parse_page(html_content): 解析单页电影数据 tree html.fromstring(html_content) movies [] for item in tree.xpath(//div[classitem]): movie { title: item.xpath(.//span[classtitle][1]/text())[0], rating: float(item.xpath(.//span[classrating_num]/text())[0]), votes: int(item.xpath(.//div[classstar]/span[last()]/text())[0].replace(人评价, )), quote: item.xpath(.//span[classinq]/text())[0] if item.xpath(.//span[classinq]/text()) else , url: item.xpath(.//div[classhd]/a/href)[0] } movies.append(movie) return movies处理分页逻辑时我们观察到豆瓣的翻页URL规律明显第1页https://movie.douban.com/top250 第2页https://movie.douban.com/top250?start25filter 第3页https://movie.douban.com/top250?start50filter ...基于此规律我们可以构建完整的分页爬取流程def crawl_top250(): 爬取完整Top250榜单 base_url https://movie.douban.com/top250 all_movies [] for start in range(0, 250, 25): url f{base_url}?start{start}filter if start 0 else base_url print(f正在抓取: {url}) html_content get_page(url) if html_content: all_movies.extend(parse_page(html_content)) time.sleep(3) # 礼貌性延时 return all_movies4. 数据存储与后续处理获取到的数据可以保存为多种格式这里我们展示最常用的CSV和JSON两种方式def save_data(movies, formatcsv): 保存电影数据 df pd.DataFrame(movies) if format csv: df.to_csv(douban_top250.csv, indexFalse, encodingutf_8_sig) elif format json: df.to_json(douban_top250.json, orientrecords, force_asciiFalse) else: raise ValueError(不支持的格式请选择csv或json)调用示例if __name__ __main__: movies crawl_top250() save_data(movies, csv) print(f成功抓取{len(movies)}部电影数据)5. 高级技巧与异常处理在实际爬取过程中可能会遇到各种异常情况。以下是几个常见问题的解决方案反爬虫应对策略随机User-Agent使用fake_useragent库生成随机头部from fake_useragent import UserAgent ua UserAgent() HEADERS[User-Agent] ua.randomIP代理池对于大规模爬取建议使用代理服务PROXIES {http: http://your.proxy:port} resp requests.get(url, headersHEADERS, proxiesPROXIES)数据清洗技巧评价人数字段原始值为1234567人评价我们需要提取数字部分votes_text item.xpath(.//div[classstar]/span[last()]/text())[0] votes int(votes_text.replace(人评价, ).replace(,, ))缺失值处理不是所有电影都有经典台词因此需要判断quote item.xpath(.//span[classinq]/text())[0] if item.xpath(.//span[classinq]/text()) else None6. 数据分析延伸应用获取到数据后我们可以进行各种有趣的分析# 读取数据 df pd.read_csv(douban_top250.csv) # 评分分布分析 rating_dist df[rating].value_counts().sort_index() print(评分分布\n, rating_dist) # 评价人数Top10 top10_voted df.sort_values(votes, ascendingFalse).head(10)[[title, votes]] print(\n评价人数Top10\n, top10_voted) # 评分与评价人数关系 df.plot.scatter(xrating, yvotes, logyTrue, title评分 vs 评价人数)通过这些分析我们可以发现哪些电影叫好又叫座哪些是高分小众作品等有趣现象。