首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >零基础学 Python 爬虫:采集网页、清洗 CSV、生成分析结果

零基础学 Python 爬虫:采集网页、清洗 CSV、生成分析结果

原创
作者头像
LeoCrawls
发布2026-09-15 15:42:47
发布2026-09-15 15:42:47
1010
举报

很多人刚学 Python 数据采集时,会把注意力全放在“怎么把网页抓下来”。

我刚开始也这样。代码跑通,终端里打印出一大片 HTML,就以为事情已经完成了一半。后来真正做项目才发现,网页采集只占很小一部分。数据能不能去重、能不能统一格式、最后能不能回答一个具体问题,才决定这份数据有没有用。

所以这篇不讲复杂反爬,也不碰登录、验证码和高频请求。我用一个公开的练习网站,带你从头跑通三个步骤:

  • 用 Python 采集网页数据;
  • 用 Pandas 清洗脏数据;
  • 统计作者和标签,生成分析结果。

如果你是零基础,先把这条完整流程跑通,比一开始研究代理、并发和浏览器自动化更合适。

准备 Python 环境

先确认电脑安装了 Python 3.10 或更高版本。

在终端执行:

代码语言:javascript
复制
python --version

然后安装本次要用的库:

代码语言:javascript
复制
pip install requests beautifulsoup4 pandas matplotlib

四个库分工很清楚:

  • requests:发送网页请求;
  • BeautifulSoup:从 HTML 中提取内容;
  • pandas:清洗和统计数据;
  • matplotlib:生成简单图表。

建议新建一个文件夹,再创建 main.py 文件。后面的代码全部放进这个文件即可。

先采集网页数据

本次使用 quotes.toscrape.com。这是专门供采集练习使用的网站,页面中包含名言、作者和标签,还有分页结构。

先看采集部分:

代码语言:javascript
复制
from pathlib import Pathimport time​import requestsimport pandas as pdfrom bs4 import BeautifulSoup​​BASE_URL = "https://quotes.toscrape.com/page/{}/"​HEADERS = {    "User-Agent": (        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "        "AppleWebKit/537.36 Chrome/124.0 Safari/537.36"    )}​​def collect_quotes(max_pages=5):    records = []    session = requests.Session()​    for page in range(1, max_pages + 1):        url = BASE_URL.format(page)        print(f"正在采集:{url}")​        response = session.get(            url,            headers=HEADERS,            timeout=10        )        response.raise_for_status()​        soup = BeautifulSoup(response.text, "html.parser")        quote_blocks = soup.select(".quote")​        if not quote_blocks:            break​        for block in quote_blocks:            quote = block.select_one(".text").get_text(                strip=True            ).strip("“”")​            author = block.select_one(".author").get_text(                strip=True            )​            tags = [                tag.get_text(strip=True)                for tag in block.select(".tag")            ]​            records.append({                "quote": quote,                "author": author,                "tags": "|".join(tags),                "source_url": url            })​        if not soup.select_one("li.next a"):            break​        time.sleep(1)​    return pd.DataFrame(records)

这段代码做了几件事。

首先,requests.Session() 会复用连接,比每次单独请求稍稳一些。其次,每个请求都设置了十秒超时,避免网络异常时程序一直卡住。最后,每采完一页暂停一秒,不连续轰炸网站。

我通常会保留 source_url 字段。以后发现某条数据不对,可以直接回到原页面核查。很多新手为了让表格看起来干净,会过早删除来源字段,后面排错反而更麻烦。

清洗采集结果

采集下来的数据不要直接拿去分析。先保留一份原始文件,再生成清洗后的版本。

代码语言:javascript
复制
def clean_quotes(df):    cleaned = df.copy()​    cleaned["quote"] = (        cleaned["quote"]        .str.replace(r"\s+", " ", regex=True)        .str.strip()    )​    cleaned["author"] = (        cleaned["author"]        .str.replace(r"\s+", " ", regex=True)        .str.strip()    )​    cleaned["tags"] = cleaned["tags"].apply(        lambda value: "|".join(            sorted({                tag.strip().lower()                for tag in value.split("|")                if tag.strip()            })        )    )​    cleaned = cleaned.dropna(        subset=["quote", "author"]    )​    cleaned = cleaned[        (cleaned["quote"] != "")        & (cleaned["author"] != "")    ]​    cleaned = cleaned.drop_duplicates(        subset=["quote", "author"]    )​    cleaned["quote_length"] = (        cleaned["quote"].str.len()    )​    return cleaned.reset_index(drop=True)

这里主要处理四类问题:

  • 删除多余空格;
  • 过滤空内容;
  • 统一标签格式;
  • 按“名言加作者”去重。

去重时不要只按作者判断。一个作者可能有多条名言,只保留一条会误删正常数据。相反,只按名言去重也可能遇到同一句话被不同页面重复收录。实际项目中,去重字段要根据业务含义确定。

quote_length 是一个派生字段。它不是网页直接提供的,而是根据名言文本计算出来的,后面可以用来观察文本长度。

做第一轮数据分析

零基础的数据分析不用一上来就做复杂模型。先回答三个简单问题:

  • 一共采集了多少条记录?
  • 哪些作者出现得最多?
  • 哪些标签最常见?
代码语言:javascript
复制
def analyze_quotes(df):
    print(f"\n清洗后记录数:{len(df)}")
    print(f"作者数量:{df['author'].nunique()}")
    print(
        f"平均文本长度:"
        f"{df['quote_length'].mean():.1f}"
    )

    author_top = (
        df["author"]
        .value_counts()
        .head(10)
    )

    tag_data = (
        df.assign(tag=df["tags"].str.split("|"))
        .explode("tag")
    )

    tag_top = (
        tag_data.loc[tag_data["tag"] != "", "tag"]
        .value_counts()
        .head(10)
    )

    print("\n出现次数最多的作者:")
    print(author_top)

    print("\n出现次数最多的标签:")
    print(tag_top)

    return author_top, tag_top

这里的 value_counts() 用于统计每个值出现的次数。

标签稍微特殊一点。一条名言可能同时带有多个标签,所以需要先用 split() 拆分,再通过 explode() 把一行展开成多行,最后才能准确计数。

这也是数据清洗中很常见的情况:原始字段适合展示,不一定适合统计。分析之前,往往要先调整数据结构。

保存数据和分析图

最后补上文件保存与可视化代码:

代码语言:javascript
复制
def save_chart(author_top):    Path("output").mkdir(exist_ok=True)​    chart_data = author_top.sort_values()​    ax = chart_data.plot(        kind="barh",        figsize=(9, 6),        color="#4C78A8"    )​    ax.set_title("Top Authors by Quote Count")    ax.set_xlabel("Quote Count")    ax.set_ylabel("Author")​    figure = ax.get_figure()    figure.tight_layout()    figure.savefig(        "output/top_authors.png",        dpi=150    )​​def main():    Path("data").mkdir(exist_ok=True)​    raw_df = collect_quotes(max_pages=5)​    if raw_df.empty:        raise RuntimeError("未采集到数据,请检查网络或页面结构。")​    raw_df.to_csv(        "data/raw_quotes.csv",        index=False,        encoding="utf-8-sig"    )​    clean_df = clean_quotes(raw_df)​    clean_df.to_csv(        "data/clean_quotes.csv",        index=False,        encoding="utf-8-sig"    )​    author_top, tag_top = analyze_quotes(clean_df)​    author_top.rename("count").to_csv(        "data/author_top.csv",        encoding="utf-8-sig"    )​    tag_top.rename("count").to_csv(        "data/tag_top.csv",        encoding="utf-8-sig"    )​    save_chart(author_top)​    print("\n处理完成,结果已保存到 data 和 output 目录。")​​if __name__ == "__main__":    main()

把前面的代码按顺序放在同一个 main.py 文件中,然后执行:

代码语言:javascript
复制
python main.py

正常情况下,你会得到这些文件:

代码语言:javascript
复制
data/├── raw_quotes.csv├── clean_quotes.csv├── author_top.csv└── tag_top.csv​output/└── top_authors.png

其中,raw_quotes.csv 是未经修改的原始数据,clean_quotes.csv 是清洗后的数据。两份都保留,方便后续核对。

运行失败时先检查什么

第一次运行,常见问题基本集中在下面几类。

如果提示 ModuleNotFoundError,说明依赖库没有安装成功。根据报错中的库名重新执行 pip install

如果提示连接超时,可以先在浏览器里打开目标网站,确认当前网络能够访问,再适当调大 timeout。不要一看到超时就直接加并发,那通常只会让问题更难判断。

如果程序正常运行但结果为空,通常是网页结构发生变化。可以打印一小段 HTML 检查:

代码语言:javascript
复制
print(response.text[:500])

如果页面内容正常,就重新核对 .quote.text.author 这些 CSS 选择器。

零基础下一步学什么

跑完这个项目后,我建议按下面的顺序继续练习:

  1. 给采集函数增加失败重试和日志记录;
  2. 学习 CSV、Excel、JSON 三种常见数据格式;
  3. 使用 Pandas 处理缺失值、异常值和日期字段;
  4. 学习分组统计、透视表和多条件筛选;
  5. 最后再接触浏览器自动化、代理调度和并发采集。

顺序不要反过来。

我见过不少刚入门的人,第一周就开始研究代理池和多线程,结果连重复数据都没处理,采集十万条后才发现真正能用的不到一半。对零基础来说,先保证数据采得准、洗得干净、能够回答问题,比单纯追求采集数量重要得多。

还有一条边界需要提前说清楚:练习时优先使用公开测试站点、自有页面或已经获得授权的数据源。正式采集前要查看网站条款、访问限制和数据使用要求,不绕过登录、验证码或明确的访问控制。

把这套流程跑通,你就已经完成了一个最小但完整的数据项目:从网页获得原始数据,整理成结构化表格,再用统计结果回答具体问题。后面换成商品、资讯或公开目录,底层思路不会有太大变化。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 准备 Python 环境
  • 先采集网页数据
  • 清洗采集结果
  • 做第一轮数据分析
  • 保存数据和分析图
  • 运行失败时先检查什么
  • 零基础下一步学什么
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档