☰
Python网页数据自动录入Excel:从爬虫到表格的完整方案
2026/10/24 6:07:41 网站建设 项目流程

没接触过爬虫的人,一听到“网页数据录入Excel”,第一反应多半是复制、粘贴、再清洗,一条一条地弄。但凡是干过几次这种重复劳动,都会觉得不对劲:网页上明明有几百上千条数据,靠手工录到表格里,又慢又容易错。后来我给自己写了一套小工具,用Python把网页里的目标数据抓下来,再直接写进Excel,整个过程几分钟就跑完。今天把这个思路完整地拆开聊一聊,包含方案选型、代码实现、踩坑实录,让不写代码的同事看完也能动手试一把。

这个“网页数据录入Excel”的解决方案,本质上是三个环节的组合:抓取网页内容、解析筛选出需要的数据、把结构化结果写入Excel表格。需要的基础是懂一点点HTML标签、会安装Python库,不需要数学编程基础。适合四类人看:经常要看网页做报表的运营、电商选品和比价的人、被重复粘贴折磨的职场新人、想用代码解决日常问题但不知道从哪入手的开发者。

我这里用的组合是requests+BeautifulSoup+openpyxl,这也是这个场景里最稳妥、最省心的技术栈。下面按完整流程来讲。

1. 为什么选择“脚本解决”这条路

1.1 先看几个真实场景

先说个我遇到的典型需求。某运营同事负责每周整理竞品线上商城的商品价格和库存,光这一件事,每周要花掉大半天时间:打开网页、逐条复制名称、价格、上下架状态,再贴进Excel,还要顺手调整格式来保证表格干净。最麻烦的是,同样操作下周还要再做一遍,一点技术含量都没有,还容易在复制粘贴中漏掉一行。

类似的场景非常多:

  • 从行业公示网站收集一批企业名单、编号、状态信息。
  • 把电商平台某个分类下的商品名称、价格、链接整理成比价表。
  • 从技术文档或新闻列表页批量获取标题、发布时间、摘要。
  • 把网页表格(HTML table)里的数据整体转换为Excel表格。

这些场景有一个共同特点:数据已经存在于网页上,结构是规律的,只是没有一个直接的“下载Excel”按钮。所以真正需要的,不是一个复杂的大数据平台,而是一个能“把网页上的结构化信息搬进表格”的机械化流程。

1.2 复制粘贴为什么不是长久之计

手工复制粘贴最大的问题不是慢,而是不可控。你永远不知道自己是不是漏掉了某一行,也不知道网页加载出来的数据在粘贴后有没有发生错位。尤其是数据量超过几十条之后,肉眼很难逐条检查。

除此之外,重复性操作还带来一个隐藏成本:注意力消耗。人的精力放在机械操作上,就没法去思考数据本身的意义。用脚本代替重复劳动,并不是懒人想法,而是把时间留给真正需要判断的事,比如检查数据差异、分析价格走势、发现异常项。

1.3 方案选型:为什么是Python三件套

做网页数据采集,可选的技术路线其实不少。可以写浏览器插件,也可以用现成的图形化工具,还可以用Python写脚本。几个方案对比之后,我最终一直推荐“Python + requests + BeautifulSoup + openpyxl”这套组合,原因是:

  • requests负责网络请求,代码量极小,十几行就能拿到网页HTML源码。
  • BeautifulSoup解析HTML的逻辑很贴近人的思维,可以像“在网页里找元素”一样写选择器,不用写复杂正则表达式。
  • openpyxl直接操作.xlsx文件,能做样式、能设置列宽、能追加数据,不需要经过CSV中转。
  • 组合起来一共只有三个依赖库,环境搭建成本低,初学者也能在一个下午跑通。

也有人问,为什么不用Selenium这种自动化浏览器工具?这个后面会专门讲,这里先说结论:如果你的目标网页是纯静态的,打开就能看到数据,用Selenium属于“杀鸡用牛刀”,启动浏览器、加载页面带来的时间开销和稳定性问题都会被无限放大。

2. 动手前必须做好的准备工作

2.1 环境搭建与镜像源配置

开始写代码前,先把Python环境理顺。我建议从头建一个干净的虚拟环境,避免和系统里其他项目冲突。命令行窗口执行:

python -m venv venv

Windows下激活虚拟环境:

venv\Scripts\activate

macOS/Linux下激活:

source venv/bin/activate

然后安装三个库:

pip install requests beautifulsoup4 openpyxl

如果下载速度不理想,可以临时指定一个国内PyPI镜像源,下载速度会快很多。这类镜像源在网上非常多,随便选一个稳定可用的即可。

注意:不要图省事直接pip install bs4之后不装beautifulsoup4,这两个包名对应不同的发行版本。推荐直接安装beautifulsoup4,这样在脚本里from bs4 import BeautifulSoup才能正常工作。

2.2 网页结构基础:先看懂HTML再说

写爬虫脚本,本质上就是在HTML里“找东西”,所以起码要看得懂最基本的标签长什么样。一个最简单的网页条目,结构通常是这样的:

<div class="product-item"> <span class="title">无线鼠标</span> <span class="price">¥89.00</span> <a href="/detail/123">查看详情</a> </div>

这里面涉及三个HTML核心概念:

  • 标签(tag):div、span、a这些尖括号包裹的标记。
  • 属性(attribute):标签里的class="product-item"就是属性,用来标记元素的类别或身份。
  • 层级关系:外层div里面包裹了多个子元素,这就是HTML的树状结构。

爬虫的解析逻辑,就是根据这些标签和属性,把目标数据“摘”出来。这个过程跟在超市里按货架标签找商品差不多:先定位到货架(外层容器),再拿想要的那几样(名称、价格、链接)。

2.3 用浏览器开发者工具定位目标元素

打开目标网页后,按F12打开开发者工具,使用左上角的“选取元素”按钮,点击页面上你想要的数据,右侧Elements面板会自动定位到对应的HTML代码。这时需要做的只是观察:

  • 每条数据是不是都在同一个容器标签里?
  • 名称、价格、链接分别用了什么class属性?
  • 数据是在HTML源码里直接可见,还是需要等页面JS加载之后才出现?

最后这个问题特别关键,它直接决定了你用静态请求还是自动化浏览器。判断方法很简单:在Elements面板里看到的数据,如果右键“查看网页源代码”也能找到,就说明是静态数据;如果源代码里没有,只有Elements里能看到,那就是动态加载,静态方案要换思路。

3. 核心代码实现:从网页到Excel的完整流程

3.1 一次合格的网页请求长什么样

写爬虫最容易犯的错,是不带任何请求头直接requests.get(url),然后莫名其妙被拦截。很多网站不仅看你的IP,还看请求头里的User-Agent,一个普通浏览器的UA和一个Python脚本默认UA,服务器的回应完全不一样。

一个比较规范的请求是这样:

import requests headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9", } resp = requests.get("https://example.com/products", headers=headers, timeout=10) resp.raise_for_status() # 状态码不是200时抛出异常,避免继续往下执行 resp.encoding = resp.apparent_encoding # 自动识别网页编码,防中文乱码 html = resp.text

这几个细节都有原因:

  • User-Agent改成浏览器的UA,是为了让服务器觉得“这是一个正常用户在访问”。
  • timeout=10是网络超时限制,防止某个请求卡住导致整个脚本停摆。
  • resp.encoding = resp.apparent_encoding是为了解决中文编码乱码,中文网页常见的编码有UTF-8和GBK,手动指定容易出错,让requests自动探测最省事。

3.2 解析HTML并提取数据

拿到HTML字符串之后,交给BeautifulSoup解析:

from bs4 import BeautifulSoup soup = BeautifulSoup(html, "html.parser") items = soup.select("div.product-item")

soup.select()接收的是CSS选择器,这个语法对熟悉前端的人零成本。不熟悉也没关系,记住几种常用写法就行:

  • select("div"):选择所有div标签。
  • select(".price"):选择所有class包含price的元素。
  • select("#main"):选择id等于main的元素。
  • select("div.product-item .title"):选择class为product-item的div里面的、class为title的所有元素。

拿到列表之后,逐条提取字段:

for item in items: title = item.select_one(".title") price = item.select_one(".price") link = item.select_one("a") if not title or not price: continue # 缺字段的就跳过,别硬处理 product_name = title.get_text(strip=True) product_price = price.get_text(strip=True) product_link = link.get("href", "") if link else ""

select_one()只取第一个匹配元素,适合已知每个条目里只有一个目标字段的情况。get_text(strip=True)获取元素里的纯文本并去掉首尾空格,get("href", "")取链接属性,取不到就返回空字符串。

这里有个经验:解析的时候别写得太“死”。比如价格字段刚才还是£89.0,过两天网页结构改成₽89.0,那脚本就抓不到了。更稳妥的做法是只取字段内部的关键文本,不要硬编码完整的匹配文本。

3.3 数据清洗环节:不要原样写入

网页上提取出来的数据,很少是“干净”的。价格可能带货币符号,库存状态可能混着一堆空白字符,链接可能是相对路径。所以写入Excel之前,需要做一次简单的数据清洗。

拿价格举例,常见处理方式:

import re price_text = "¥ 89.00" price_clean = re.sub(r"[^\d.]", "", price_text) # 只保留数字和小数点 price_value = float(price_clean)

链接如果是相对路径,要拼接成完整URL:

from urllib.parse import urljoin full_url = urljoin("https://example.com", product_link)

清洗的目标不是把数据改得漂亮,而是让Excel里的数据格式统一,方便后面做筛选、排序、求和。如果带货币符号直接写入,你会发现Excel里“求和”根本算不出来。

3.4 用openpyxl写入Excel并处理格式

写入环节来看代码:

from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment wb = Workbook() ws = wb.active ws.title = "商品清单" ws.append(["商品名称", "价格(元)", "商品链接"]) for name, price, url in cleaned_data: ws.append([name, price, url])

追加表头和数据都用ws.append(),它会自动在下一空行写入。但光写入还不够,一个让读者舒服的Excel至少应该做到三点:

  • 表头加粗,底色加深,和数据区域区分开。
  • 列宽根据内容自动调整。
  • 价格列设置数字格式,单位为元,保留两位小数。

代码是这样的:

header_font = Font(color="FFFFFF", bold=True) header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") for cell in ws[1]: cell.font = header_font cell.fill = header_fill cell.alignment = Alignment(horizontal="center") ws.column_dimensions["A"].width = 30 ws.column_dimensions["B"].width = 12 ws.column_dimensions["C"].width = 40 for row in ws.iter_rows(min_row=2, min_col=2, max_col=2): for cell in row: cell.number_format = "0.00" wb.save("网页数据.xlsx")

注意:ws[1]是第一行的所有单元格;column_dimensions设置列宽,需要手动指定合理的宽度,Excel没有“自动最适合列宽”的默认设置。

3.5 完整脚本:一套可以直接抄的流程

把前面的部分拼起来,就是一套从URL到Excel的完整脚本。我习惯把项目拆成三个文件:spider.py负责抓取解析,cleaner.py负责清洗,exporter.py负责写Excel。不过,对于一次性任务,写一个脚本文件完全够用。完整核心逻辑如下:

import re import requests from bs4 import BeautifulSoup from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment from urllib.parse import urljoin BASE_URL = "https://example.com/products" HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", } def fetch_html(url): resp = requests.get(url, headers=HEADERS, timeout=10) resp.raise_for_status() resp.encoding = resp.apparent_encoding return resp.text def parse_products(html): soup = BeautifulSoup(html, "html.parser") results = [] for item in soup.select("div.product-item"): title_el = item.select_one(".title") price_el = item.select_one(".price") link_el = item.select_one("a") if not title_el or not price_el: continue name = title_el.get_text(strip=True) price_text = price_el.get_text(strip=True) price_value = float(re.sub(r"[^\d.]", "", price_text)) href = link_el.get("href", "") if link_el else "" full_url = urljoin(BASE_URL, href) results.append([name, price_value, full_url]) return results def save_to_excel(data, filename="网页数据.xlsx"): wb = Workbook() ws = wb.active ws.title = "商品清单" ws.append(["商品名称", "价格(元)", "商品链接"]) for row in data: ws.append(row) header_font = Font(color="FFFFFF", bold=True) header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") for cell in ws[1]: cell.font = header_font cell.fill = header_fill cell.alignment = Alignment(horizontal="center") ws.column_dimensions["A"].width = 30 ws.column_dimensions["B"].width = 12 ws.column_dimensions["C"].width = 60 for row in ws.iter_rows(min_row=2, min_col=2, max_col=2): for cell in row: cell.number_format = "0.00" wb.save(filename) if __name__ == "__main__": html = fetch_html(BASE_URL) clean_data = parse_products(html) save_to_excel(clean_data) print(f"完成,共写入 {len(clean_data)} 条数据")

这段代码已经能覆盖绝大多数静态网页的数据采集需求。

4. 完整演示案例:从商品列表抓取到Excel

4.1 演示目标与关键分析

为了把前面几个章节串起来,我给一个真实的模拟案例,目标是一个商品列表页,页面上有多条商品信息,结构固定。我们要做的事情是:抓取所有商品名称、价格、链接,清洗后保存成一份带表头的Excel文件。

打开页面F12后,观察到以下结构:

<div class="product-item"> <span class="title">樱桃机械键盘</span> <span class="price">¥ 349.00</span> <a href="/goods/1001">详情</a> </div>

这说明每条商品都在div.product-item里,名称在.title,价格在.price,链接在条目里的a标签。这就是前面代码里选择器写法的来源。

4.2 运行流程与结果验证

在命令行执行脚本:

python spider.py

正常情况下输出:

完成,共写入 36 条数据

打开生成的Excel文件,可以看到:

商品名称价格(元)商品链接
樱桃机械键盘349.00https://example.com/goods/1001
无线静音鼠标89.00https://example.com/goods/1002

检查时不要只看条数,随手抽查三行数据,把Excel里的内容和网页实际内容比对一下。重点检查三处:价格小数位是否正确、链接是否完整、是否有空行混入。

4.3 如何把脚本泛化成通用工具

实际工作中,需求不大可能是“永远抓同一个页面”。更多情况是“换个页面再抓一遍”。所以脚本里的选择器和URL最好抽出来,作为配置项,放在脚本顶部的变量区域。

我一般会这样做:

CONFIG = { "url": "https://example.com/products", "container_selector": "div.product-item", "fields": { "name": ".title", "price": ".price", "link": "a", }, "excel_name": "商品清单.xlsx", }

每次换新页面,只需要改CONFIG字典,改完后再跑一次,确认新页面的结构匹配。如果新页面结构差异太大,再微调选择器即可。

4.4 多页翻页抓取思路

网页数据如果分布在多页,可以做一个翻页的循环。常见翻页URL有两种形式:一是URL里有页码参数,二是点击“下一页”按钮触发请求。

URL页码形式的处理最简单:

for page in range(1, 6): page_url = f"https://example.com/products?page={page}" html = fetch_html(page_url) data.extend(parse_products(html)) time.sleep(1) # 每页之间延迟1秒,降低对目标站点的压力

这里加time.sleep(1)不是磨蹭,而是基本的访问礼节。爬虫和普通浏览器的区别在于速度快,如果每秒钟请求几十个页面,服务器很容易判断为异常访问。主动降低请求频率,是避免被封号的最简单手段。

5. 那些年我们踩过的坑:常见问题排查实录

5.1 网页元素抓不到?可能是动态加载

最常遇到的坑是:用requests请求后,发现HTML源码里根本没有目标数据。这时候先在浏览器里看整个HTML源码,搜索目标字段,如果搜索不到,说明数据是通过JavaScript发请求后用脚本渲染上去的,静态请求拿不到完整内容。

这时的处理路径有三条:

  • 找到页面背后的数据接口(往往是一个JSON API),直接请求接口拿数据,效率最高。
  • 改用Selenium或Playwright做自动化浏览器,让真实浏览器渲染完成后再解析。
  • 放弃页面渲染,直接在HTML里找服务器预埋的数据变量,有时也能挖到。

判断到底用哪条路径,取决于对方站点是否提供了一种不需要完整页面渲染的数据来源。很多网页为了前后端分离,都会有一个直接返回JSON的接口,找到这个接口,连BeautifulSoup都可以省掉。

5.2 中文乱码问题

中文乱码十有八九是编码判断错误。解决方案就是前面代码里那句:

resp.encoding = resp.apparent_encoding

apparent_encoding是requests根据HTTP头、HTML 声明、内容统计推测出来的编码。多数情况下它是对的,但偶尔也会猜错。如果遇到中文乱码,可以自己打印resp.apparent_encoding值,再手动指定一次。比如网站明确是GBK编码:

resp.encoding = "gbk"

5.3 被反爬限制:返回403或验证码

请求返回403,大多是反爬策略生效。优先检查是否缺少User-Agent。然后检查是否需要添加Referer,很多站点会校验请求来源,Referer必须是目标页面本身的域名才放行。再不行可以加Cookie,模拟一个已登录用户的状态。

反爬这块的重点是不做对抗,而是减少特征:

  • 降低请求频率,加随机延迟。
  • 随机化User-Agent,多备用几个浏览器UA。
  • 遇到重要数据页面,优先找公开的数据接口。

注意:采集公共数据之前,一定先看目标网站的条款。本文讨论的是自动化办公场景下的数据整理,所有实践都应限定在允许访问的公开信息范围内。

5.4 写入Excel后数字格式不对

价格写入Excel后如果变成文本格式,求和时会出问题。根因是清洗环节没把字符串转成float,写入Excel的仍是文本。检查方式很简单:在Excel里点击该列单元格,看编辑栏显示的是数字还是文本。如果是文本,回到清洗代码,确认float()转换是否成功执行。

还有一种情况是价格字段里混入了逗号千分位,比如1,299.00,这时候用re.sub(r"[^\d.]", "", price_text)会把逗号删掉,变成1299.00,正好处理干净。

5.5 常见问题速查表

现象根因解决方案
返回403缺请求头或触发反爬补全UA/Referer,降低频率
中文乱码编码判断错误resp.encoding = resp.apparent_encoding
目标数据为空动态加载找JSON接口或改用Selenium
Excel里价格求和为0价格是文本格式清洗时float()数字格式化
链接只有相对路径页面内链接是相对路径用urljoin拼接完整URL
某条数据缺字段报错页面上有空条目字段缺失时continue跳过

5.6 独家避坑技巧:先用本地文件调试

一个我常年使用的调试习惯:先不直接请求线上网页,而是把网页HTML源码保存到本地,先用本地文件跑通解析和写入逻辑。

with open("page.html", "r", encoding="utf-8") as f: html = f.read() soup = BeautifulSoup(html, "html.parser")

这样做的价值在于:解析逻辑不会受到网络波动、反爬拦截的影响,出错时可以基于同一份HTML反复调试选择器。等本地解析完全正确了,再把逻辑接回requests,一次性跑通。尤其是选择器写不对的时候,这招能把调试时间压缩一半以上。

6. 进阶玩法:让这套方案更“程序员范儿”

6.1 用pandas替代手写清洗逻辑

当数据量变大、字段变多之后,逐条清洗和写入的手写逻辑会越来越繁琐。这时候可以引入pandas,把数据先组装成二维表,再一行代码导出Excel。

import pandas as pd df = pd.DataFrame(data, columns=["商品名称", "价格", "商品链接"]) df["价格"] = pd.to_numeric(df["价格"], errors="coerce") df.to_excel("网页数据.xlsx", index=False)

pandas的优势在于表格处理能力:可以直接筛选、排序、去重、分组统计,甚至还能从多个网页抓来的数据做横向合并。适合需要做进一步分析的场景。

6.2 定时自动采集

脚本跑通之后,下一步自然是让它自动跑。Windows下可用任务计划程序,“触发器”设置每周或每天执行一次,“操作”指定需要执行的Python命令,就会在指定时间自动运行脚本并生成新的Excel文件。

macOS或Linux下用crontab:

0 9 * * 1 cd /path/to/project && /path/to/venv/bin/python spider.py

上面的意思是每周一早上9点执行一次。固定时间自动采集的最大好处是,你只需要在数据真正变化的那一天打开Excel看结果,其他时间完全不用管。

6.3 处理动态网页的进阶方案:Selenium什么时候才用

强调一下,Selenium不是首选方案,而是兜底方案。只有在确认目标页面是动态渲染、且找不到数据接口的时候,才用Selenium。它启动浏览器、加载页面、点击翻页,真实模拟人的操作,能拿到完整渲染后的HTML。

用Selenium的简单示例:

from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() options.add_argument("--headless") # 无界面模式,不弹浏览器窗口 driver = webdriver.Chrome(options=options) driver.get("https://example.com/products") html = driver.page_source driver.quit()

拿到的HTML再交给BeautifulSoup解析,后续流程完全一样。但要清醒地认识到:Selenium的启动开销大、运行速度慢、对资源占用高,只适合少量动态页面。

6.4 这套方案的边界

这个方案能解决“网页数据录入Excel”,但并不适合所有场景。比如大规模爬取、需要登录的复杂系统、高度反爬的站点,这些都需要更专业的工程化手段,不在本文讨论范围内。

对手头这个需求——把网页上公开可见的结构化数据整理成Excel——脚本方案已经做到了“低成本、可复制、免重复劳动”这三件事,剩下的就是随用随改。

最后说点个人体会。我见过很多同事第一次跑通脚本时的表情:有点不敢相信网页数据真的自己进了Excel。但你真把这个流程跑通之后,会觉得它其实没什么高深的地方——拆解问题、选工具、写循环、调格式,每一步都是可以学习的经验。这个方案后续还能扩展成定时任务、邮件自动推送、图表自动生成,全看你的想象力。动手是第一步,别想太多,装好环境,复制这段代码,换上你自己的网页地址,跑一下试试。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询