ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python爬虫实战:双十一商品数据抓取与Excel分析全流程

Python爬虫实战:双十一商品数据抓取与Excel分析全流程 1. 项目缘起为什么要在双十一用Python抓商品数据又到一年双十一铺天盖地的优惠券、满减规则和直播预告看得人眼花缭乱。作为一个既想省钱又怕麻烦的“技术型”消费者我每年都会遇到同样的困境想对比不同平台、不同店铺的同款商品价格手动一个个去搜、去记不仅效率低下还容易遗漏。更重要的是很多所谓的“历史最低价”和“预售优惠”如果不把数据拉出来横向对比根本看不出门道。今年我决定不再被动。与其被复杂的营销规则牵着鼻子走不如主动出击用Python写个脚本把感兴趣的商品信息都抓下来存到Excel里慢慢分析。这听起来像是个“爬虫”项目没错它的核心确实是网络数据抓取。但它的目的不是为了“爬”而“爬”而是为了解决一个非常具体的消费决策问题在信息爆炸的购物节里如何高效、准确地获取并管理商品数据从而做出更明智的选择这个项目适合所有对Python有基础了解并且受困于信息筛选的朋友。无论你是想为自己“剁手”做参谋还是想学习如何将Python应用于解决实际生活问题甚至是为电商数据分析做入门练习接下来的内容都会给你一套可以直接“抄作业”的完整方案。我们将从环境搭建开始一步步走到数据保存过程中我会分享我踩过的坑和总结的技巧。2. 环境与工具准备搭建你的数据分析工作台工欲善其事必先利其器。在开始写代码之前我们需要一个稳定、高效的开发环境。这个环境的核心是Python解释器和一个好用的代码编辑器或集成开发环境IDE。2.1 Python安装与包管理首先确保你的电脑上安装了Python。我强烈推荐使用Python 3.7及以上版本因为很多现代库对旧版本的支持已经停止。你可以从Python官网下载安装包安装时务必勾选“Add Python to PATH”选项这样你就可以在命令行中直接使用python和pip命令了。安装完成后打开命令行Windows上是CMD或PowerShellMac/Linux上是Terminal输入python --version来验证安装是否成功。接下来我们需要安装这个项目所需的几个核心库。我们将使用pip这是Python的包管理工具它就像是一个应用商店可以轻松安装和管理第三方代码库。这个项目主要依赖以下三个库requests 用于向网站发送HTTP请求获取网页的HTML源代码。它是我们获取数据的“手”。BeautifulSoup4 (bs4) 用于解析HTML源代码从中提取出我们需要的结构化信息比如商品标题、价格、链接。它是我们理解网页内容的“大脑”。pandas 这是一个功能强大的数据分析库。我们这里主要用它来将抓取到的数据整理成表格DataFrame并轻松地导出为Excel文件。它是我们整理和输出数据的“流水线”。在命令行中一次性安装它们pip install requests beautifulsoup4 pandas openpyxl这里多安装了一个openpyxl因为pandas在读写新版Excel文件.xlsx格式时需要这个引擎。安装过程可能会持续一两分钟取决于你的网络速度。2.2 开发工具选择VSCode的轻量级配置对于代码编辑器我的首选是Visual Studio CodeVSCode。它免费、轻量、插件生态丰富对Python的支持非常好。如果你还没有安装可以去其官网下载。安装好VSCode后你需要进行简单的Python环境配置打开VSCode安装官方提供的“Python”扩展。在扩展市场搜索“Python”由Microsoft发布的那个就是。打开或创建一个项目文件夹然后新建一个Python文件例如double11_spider.py。在VSCode的左下角你可以看到当前选择的Python解释器版本。点击它在弹出的列表中选择你刚刚安装的Python环境。这一步确保了VSCode的代码提示、调试等功能都基于正确的环境。注意有时你可能会遇到“请安装缺失的包以使用此工作流”这类提示这通常是因为某些VSCode扩展或项目配置依赖特定的Python包。根据提示在终端里运行指定的pip install命令即可。对于我们的核心任务只要requestsbs4pandas安装成功就不会有问题。至此你的“数字矿工”工作台就搭建好了。我们有了获取数据的工具requests、解析数据的工具BeautifulSoup、处理数据的工具pandas以及一个舒适的编码环境VSCode。接下来我们就要深入“矿场”——电商网站的页面结构了。3. 目标分析与页面结构解析找到数据的藏身之处在动手写爬虫之前最重要的一步是“侦察”。我们需要弄清楚我们想要的数据商品名、价格、销量等在网页的哪个位置它们是以什么样的HTML标签和属性存在的这一步通常通过浏览器的“开发者工具”来完成。以国内某主流电商平台例如淘宝的搜索列表页为例。假设我们想抓取“蓝牙耳机”这个关键词下的商品。我们打开平台搜索“蓝牙耳机”然后按下F12键或右键点击页面选择“检查”打开开发者工具。3.1 使用开发者工具定位元素在开发者工具的“元素”Elements面板你可以看到构成当前页面的所有HTML代码。这个面板左上角有一个箭头图标或鼠标图标点击它然后将鼠标移动到网页上的某个商品区域比如商品标题你会发现对应的HTML代码区域会被高亮显示。通过反复尝试和观察你会发现在列表页中每一个商品卡片通常被包裹在一个具有特定类名class或数据属性data-*的容器div里。例如它可能看起来像这样div classJ_MouserOnverReq>import requests from bs4 import BeautifulSoup import pandas as pd import time import random def get_page_html(url): 发送HTTP请求获取网页HTML内容 # 设置请求头模拟浏览器访问 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 } try: # 发送GET请求 response requests.get(url, headersheaders, timeout10) # 检查请求是否成功状态码200 response.raise_for_status() # 设置正确的编码避免中文乱码 response.encoding response.apparent_encoding or utf-8 return response.text except requests.exceptions.RequestException as e: print(f请求页面失败: {url}) print(f错误信息: {e}) return None # 示例假设这是某个商品列表页的URL此处为示例需替换为实际可访问的URL base_url https://example.com/search?q蓝牙耳机page1 html_content get_page_html(base_url) if html_content: print(页面获取成功) else: print(页面获取失败请检查网络或URL。)这段代码定义了一个健壮的请求函数。它设置了User-Agent来伪装成浏览器使用了try-except来捕获网络请求可能出现的异常如超时、连接错误并处理了编码问题以防止中文乱码。这是编写生产级爬虫的基础。4.2 使用BeautifulSoup解析与数据提取拿到HTML字符串后我们用BeautifulSoup将其解析成一个可以遍历和搜索的树形结构。def parse_product_list(html): 解析商品列表页HTML提取商品信息 if not html: return [] soup BeautifulSoup(html, html.parser) product_list [] # 根据之前分析的页面结构找到所有商品卡片的容器 # 这里的选择器 .item.J_MouserOnverReq 是一个示例你需要根据实际页面调整 items soup.select(.item.J_MouserOnverReq) for item in items: product_info {} # 提取商品标题 title_elem item.select_one(.title a) product_info[标题] title_elem.get_text(stripTrue) if title_elem else N/A # 提取商品价格 price_elem item.select_one(.price strong) product_info[价格] price_elem.get_text(stripTrue) if price_elem else N/A # 提取商品链接可能需要补全为完整URL link_elem item.select_one(.pic a) if link_elem and link_elem.get(href): href link_elem[href] # 如果链接是相对路径则补全为绝对路径 if href.startswith(//): product_info[链接] https: href elif href.startswith(/): product_info[链接] https://example.com href # 替换为实际域名 else: product_info[链接] href else: product_info[链接] N/A # 提取商品销量 sales_elem item.select_one(.deal-cnt) product_info[月销量] sales_elem.get_text(stripTrue) if sales_elem else N/A # 提取商品ID可能从data-id属性获取 product_info[商品ID] item.get(data-id, N/A) product_list.append(product_info) # 添加一个短暂的随机延时模拟人工操作避免请求过快 time.sleep(random.uniform(0.5, 1.5)) return product_list # 使用示例 if html_content: products parse_product_list(html_content) print(f本页共解析到 {len(products)} 个商品。) for p in products[:2]: # 打印前两个商品看看 print(p)parse_product_list函数是数据提取的核心。我们使用soup.select()和soup.select_one()方法通过CSS选择器精准定位到包含信息的HTML元素。get_text(stripTrue)用于获取元素的文本并去除首尾空白。get()方法用于获取元素的属性值。代码中加入了详细的判断if ... else以防止因为某个元素缺失而导致程序崩溃。最后的time.sleep是一个重要的反反爬虫技巧。4.3 实现翻页与多页数据抓取一个搜索关键词的结果通常有多页。我们需要模拟翻页行为抓取所有页面的数据。翻页的逻辑通常是URL中有一个page参数在变化。def crawl_multiple_pages(base_keyword, max_pages5): 抓取多页商品数据 base_keyword: 搜索关键词 max_pages: 计划抓取的最大页数 all_products [] for page in range(1, max_pages 1): print(f正在抓取第 {page} 页...) # 构造每一页的URL。这里URL格式是示例需要根据实际网站调整 url fhttps://example.com/search?q{base_keyword}page{page} html get_page_html(url) if not html: print(f第 {page} 页抓取失败跳过。) continue products_on_page parse_product_list(html) all_products.extend(products_on_page) print(f第 {page} 页抓取完成获得 {len(products_on_page)} 个商品。累计 {len(all_products)} 个。) # 每抓完一页等待稍长时间避免被封IP if page max_pages: sleep_time random.uniform(2, 5) print(f等待 {sleep_time:.2f} 秒后继续下一页...) time.sleep(sleep_time) return all_products # 执行多页抓取 keyword 蓝牙耳机 all_products_data crawl_multiple_pages(keyword, max_pages3) # 先抓3页试试 print(f抓取结束总共获得 {len(all_products_data)} 条商品数据。)这个函数通过循环page参数构建每一页的URL然后重复调用get_page_html和parse_product_list。它将所有页面的结果收集到all_products列表中。翻页间的延时设置得比单页内解析延时更长进一步降低了请求频率。5. 数据清洗与保存用Pandas打造规整的Excel报表抓取到的原始数据往往存在一些问题价格可能带有“¥”符号或“起”字销量可能是“1万”这样的文本我们需要将其转换为适合分析的格式。然后用Pandas将其保存为Excel。5.1 使用Pandas进行数据清洗与转换Pandas的DataFrame是处理表格数据的利器。def clean_and_save_to_excel(product_list, filenamedouble11_products.xlsx): 清洗数据并保存到Excel if not product_list: print(没有数据可保存。) return # 将数据列表转换为Pandas DataFrame df pd.DataFrame(product_list) # 数据清洗示例 # 1. 价格清洗去除货币符号转换为浮点数 if 价格 in df.columns: # 使用正则表达式提取数字包括小数点 df[价格_数值] df[价格].str.extract(r(\d\.?\d*)).astype(float) # 你也可以选择替换掉非数字字符 # df[价格_数值] df[价格].replace(r[^\d.], , regexTrue).astype(float) # 2. 销量清洗将“1万”转换为10000“2000”转换为2000 if 月销量 in df.columns: def convert_sales(s): if isinstance(s, str): if 万 in s: num s.replace(万, ).replace(, ) try: return float(num) * 10000 except: return None else: # 去除“”等字符只留数字 num s.replace(, ) try: return float(num) except: return None return s df[月销量_数值] df[月销量].apply(convert_sales) # 3. 去重根据商品ID去重如果ID可靠 if 商品ID in df.columns and df[商品ID].notna().any(): initial_count len(df) df.drop_duplicates(subset[商品ID], keepfirst, inplaceTrue) print(f去重后数据从 {initial_count} 条减少到 {len(df)} 条。) # 4. 处理缺失值可以用特定值填充或删除 # df.fillna(N/A, inplaceTrue) # 用‘N/A’填充所有NaN # df.dropna(subset[价格_数值], inplaceTrue) # 删除价格为空的行 # 保存到Excel try: # 使用openpyxl引擎写入.xlsx文件 with pd.ExcelWriter(filename, engineopenpyxl) as writer: df.to_excel(writer, indexFalse, sheet_name商品数据) # indexFalse不保存行索引 print(f数据已成功保存到文件: {filename}) print(f共保存 {len(df)} 条记录列名为: {, .join(df.columns)}) except Exception as e: print(f保存Excel文件时出错: {e}) # 使用示例 clean_and_save_to_excel(all_products_data, 双十一蓝牙耳机商品列表.xlsx)这个清洗函数展示了几个常见操作使用str.extract进行正则提取、使用apply方法进行自定义函数转换、使用drop_duplicates进行去重。清洗后的数据如价格_数值、月销量_数值是数值类型可以直接用于后续的排序、计算和图表分析。5.2 高级技巧数据透视与多Sheet保存Pandas的能力远不止于此。我们可以对清洗后的数据做简单的分析并保存到同一个Excel文件的不同工作表Sheet中。def enhanced_analysis_and_save(df, filenamedouble11_analysis.xlsx): 进行简单分析并保存到多Sheet的Excel with pd.ExcelWriter(filename, engineopenpyxl) as writer: # Sheet1: 原始/清洗后的完整数据 df.to_excel(writer, indexFalse, sheet_name原始数据) # Sheet2: 按价格区间统计商品数量 if 价格_数值 in df.columns: # 创建价格区间 bins [0, 100, 500, 1000, 2000, 5000, float(inf)] labels [0-100, 101-500, 501-1000, 1001-2000, 2001-5000, 5000] df[价格区间] pd.cut(df[价格_数值], binsbins, labelslabels, rightFalse) price_summary df[价格区间].value_counts().sort_index() price_summary_df price_summary.reset_index() price_summary_df.columns [价格区间, 商品数量] price_summary_df.to_excel(writer, indexFalse, sheet_name价格分布) # Sheet3: 销量Top 10的商品 if 月销量_数值 in df.columns and 标题 in df.columns: top_sales df.nlargest(10, 月销量_数值)[[标题, 价格_数值, 月销量_数值, 链接]] top_sales.to_excel(writer, indexFalse, sheet_name销量Top10) # Sheet4: 简单的描述性统计 if 价格_数值 in df.columns: stats_df df[价格_数值].describe().to_frame().T # 描述性统计转成DataFrame stats_df.to_excel(writer, sheet_name数据统计) print(f增强分析报告已保存至: {filename}) # 假设df是清洗后的DataFrame # df pd.DataFrame(all_products_data) # ... 执行清洗步骤 ... # enhanced_analysis_and_save(df)这个函数创建了一个包含多个工作表的Excel文件“原始数据”存放所有信息“价格分布”展示了不同价位段的商品数量“销量Top10”列出了最畅销的商品“数据统计”则提供了价格的平均值、标准差等基本信息。这样当你打开这个Excel文件时就能获得一个初步的数据分析报告。6. 实战中的坑与应对策略理论很美好但实战中总会遇到各种意想不到的问题。下面是我在类似项目中总结的几个常见“坑”及其应对策略。6.1 请求被拒绝与反爬虫对抗这是最常见的问题。你可能遇到403 Forbidden错误或者收到的HTML里包含“访问过于频繁”的提示。策略一完善请求头Headers。只设置User-Agent往往不够。复制浏览器中真实请求的Headers在开发者工具Network面板里查看特别是Cookie、Referer有时Accept-Language、Accept-Encoding也有关。用requests的headers参数模拟。headers { User-Agent: ..., Accept: text/html,application/xhtmlxml..., Accept-Language: zh-CN,zh;q0.9, Referer: https://www.example.com/, Cookie: 你的Cookie字符串 # 谨慎使用注意隐私和时效性 }策略二使用会话Session。requests.Session()可以保持会话自动处理Cookie使多次请求更像同一个浏览器会话。session requests.Session() session.headers.update(headers) response session.get(url)策略三添加延时与随机性。这是最基本的道德和策略。在请求间使用time.sleep()并且延时时间最好随机化不要固定间隔。time.sleep(random.uniform(1, 3)) # 随机等待1到3秒策略四使用代理IP。如果单个IP被封锁可以考虑使用代理IP池来轮换IP地址。但这涉及额外成本和复杂度对于个人学习和小规模抓取优先使用前三种策略。重要提示始终尊重网站的robots.txt文件和服务条款。对于明确禁止爬取或没有公开接口的网站不要强行抓取。本项目旨在技术学习请将目标定为允许爬取的公开数据源或用于练习的测试网站。6.2 页面结构变动导致解析失败你今天写的CSS选择器可能因为网站前端的改版明天就失效了。代码报错找不到元素。策略编写健壮的解析代码。不要依赖过于复杂或脆弱的CSS路径。尽量使用具有唯一性的id或class或者结合标签和属性选择器。广泛使用if判断元素是否存在。# 更健壮的写法 price_container item.find(div, class_price) if price_container: price_elem price_container.find(strong) price price_elem.text.strip() if price_elem else N/A else: price N/A策略定期维护与日志。将关键的解析步骤和抓取到的URL记录下来。当解析失败时日志能帮你快速定位是哪一批数据或哪一个页面出了问题。可以考虑将原始HTML保存到本地文件进行调试。with open(fdebug_page_{page}.html, w, encodingutf-8) as f: f.write(html_content)6.3 数据保存与格式问题问题Excel打开乱码。这通常是因为编码问题。确保在保存为Excel时Pandas使用的是正确的引擎openpyxlfor .xlsx并且在之前处理HTML时已经正确设置了编码response.encoding。问题数值被保存为文本。在Excel中清洗后的“价格_数值”列可能还是文本格式无法求和。这通常是因为原始数据中混入了非数字字符清洗不彻底。确保在astype(float)之前字符串是纯粹的数字格式。可以使用pd.to_numeric(errors‘coerce’)函数它会将无法转换的值设为NaN。df[价格_数值] pd.to_numeric(df[价格].str.replace(r[^\d.], , regexTrue), errorscoerce)问题文件过大或写入慢。如果数据量极大数十万行一次性用to_excel写入可能会内存不足或很慢。可以考虑分块写入或者使用to_csv保存为CSV格式后者更轻量、更快。7. 项目扩展与进阶思路完成了基础的数据抓取和保存这个项目还有很多可以深化和扩展的方向让它从一个脚本变成一个真正有用的工具。7.1 构建图形化用户界面GUI对于不懂代码的朋友一个带有按钮和表格的窗口显然比运行Python脚本更友好。你可以使用tkinterPython标准库、PyQt或DearPyGui等库来构建一个简单的桌面应用。应用可以包含以下功能输入关键词和抓取页数的文本框。一个“开始抓取”按钮。一个显示抓取进度的进度条或标签。一个表格控件如tkinter的Treeview来实时展示抓取到的数据。一个“导出到Excel”按钮。这样你就创建了一个专属的“双十一比价小助手”。7.2 定时任务与自动化监控双十一的预售期很长价格可能每天都在变。你可以使用Python的schedule库或操作系统的定时任务如Linux的cron或Windows的“任务计划程序”让脚本每天定时运行。脚本可以抓取你关注商品的最新价格。与昨天保存的历史价格对比。如果发现降价幅度达到你设定的阈值比如10%就自动发送一封邮件或一条钉钉/微信消息提醒你。这就实现了价格监控自动化不错过任何一次真降价。7.3 深入数据分析与可视化有了干净的Excel数据你可以用Pandas进行更深入的分析并用matplotlib或seaborn库生成图表。价格分布直方图看看大部分蓝牙耳机集中在哪个价位段。价格-销量散点图分析价格和销量之间是否存在相关性是越便宜卖得越多还是某个中间价位最受欢迎品牌分析从标题中提取品牌信息可能需要用到正则表达式或简单分词统计哪个品牌出现的频率最高哪个品牌的平均售价最高。这些分析能帮你更深刻地理解市场而不仅仅是罗列商品列表。7.4 转向更高效的爬虫框架当项目变得复杂需要管理大量请求、处理异步、应对更复杂的反爬时可以考虑使用专业的爬虫框架如Scrapy。Scrapy提供了项目结构、异步请求引擎、中间件、管道等一套完整机制。它能让你的代码更模块化更容易扩展和维护并且性能通常比requests同步请求更高。将本项目改写成Scrapy版本是一个很好的进阶练习。从打开浏览器搜索商品到运行脚本自动获取并分析数据这个过程本身就是一个将技术应用于生活、提升效率的绝佳案例。我个人的体会是最初的难点往往在于如何精准地定位网页元素和应对网站的反爬措施。多使用浏览器的开发者工具进行练习多思考如何让你的请求看起来更“像人”这两点能解决大部分入门期的问题。最后请务必记住技术是用来创造价值的在享受自动化便利的同时一定要合法合规地使用爬虫尊重数据所有者的权益。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进