伊朗主帅:球队被勒令立即离开美国

作者:







Python网络爬虫实战:从零开始抓取网页数据


Python网络爬虫实战:从零开始抓取网页数据

简介

在网络信息爆炸的时代,如何高效地从海量网页中提取有价值的数据,是许多开发者和数据分析师面临的共同挑战。网络爬虫(Web Crawler)正是解决这一问题的核心工具。它是一种自动化程序,能够系统性地浏览互联网并收集特定信息。本教程将手把手带你使用Python及其强大的生态库,从一个真实网页中抓取结构化数据。无论你是想收集市场信息、进行学术研究,还是构建自己的数据集,掌握这项技能都将大大提升你的工作效率。我们将使用一个公开的图书信息网站作为实例,整个过程注重实战,确保你学完即可上手应用。

前置准备

在开始之前,请确保你的开发环境已准备就绪。你需要:

  1. Python环境:安装Python 3.6或更高版本。推荐使用官方安装包或Anaconda发行版。
  2. 代码编辑器:一款趁手的编辑器能极大提升编码效率。Visual Studio Code、PyCharm等都是优秀的选择。如果你正在寻找一台能流畅运行IDE的笔记本电脑,不妨关注一下高性能的开发本。
  3. 必要的Python库:我们将使用requests库发送HTTP请求,以及BeautifulSoup库解析HTML文档。
  4. 基础的HTML知识:了解HTML标签(如<div>, <a>, <h1>等)和属性(如class, id)的基本含义,这将帮助你定位网页中的数据。

打开你的终端或命令提示符,安装所需的库:

pip install requests beautifulsoup4

第一步:分析目标网页与发送请求

我们的目标是抓取 http://books.toscrape.com 这个练习网站上的图书信息(书名、价格、评分等)。

首先,我们需要用代码模拟浏览器访问网页。一个配置舒适的机械键盘能让长时间的编码过程更加愉悦。

import requests

# 目标URL
url = "http://books.toscrape.com/"

# 发送GET请求,并伪装请求头,避免被某些网站简单屏蔽
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'
}
response = requests.get(url, headers=headers)

# 检查请求是否成功 (状态码200表示成功)
if response.status_code == 200:
    print("网页获取成功!")
    # 打印网页内容的前500个字符,初步观察
    print(response.text[:500])
else:
    print(f"请求失败,状态码:{response.status_code}")

运行这段代码,你会在控制台看到网页的HTML源码片段。这证实我们已经成功“拿到”了网页的原始内容。

第二步:解析HTML并定位数据元素

拿到HTML源码后,直接处理字符串会非常痛苦。我们需要使用BeautifulSoup将其转换为一个可方便查询的“汤”(Soup)对象,并像使用CSS选择器一样精准定位数据。

from bs4 import BeautifulSoup

# 将获取到的HTML文本转换为BeautifulSoup对象
soup = BeautifulSoup(response.text, 'html.parser')

# 找到所有图书信息的容器。通过浏览器“检查元素”,我们发现每本书都在一个`<article class="product_pod">`标签里。
books = soup.find_all('article', class_='product_pod')

print(f"本页共找到 {len(books)} 本书的信息。")

第三步:提取并清洗目标数据

现在我们有了所有书籍的容器列表,接下来需要遍历每一个容器,从中提取书名、价格和评分。这个过程就像在整理一个文件柜,你需要为每份文件贴上正确的标签。一台大屏幕的显示器能让你更清晰地查看网页结构和数据。

import csv

# 创建一个列表来存储所有书籍数据
books_data = []

for book in books:
    # 提取书名:位于 `<h3>` 标签内的 `<a>` 标签的 `title` 属性中
    title = book.h3.a['title']

    # 提取价格:位于 `<p class="price_color">` 中
    price = book.find('p', class_='price_color').text

    # 提取评分:评分是通过CSS类名表示的,例如 `star-rating Three`。我们需要从类名中提取“Three”。
    rating_element = book.find('p', class_='star-rating')
    rating_class = rating_element.get('class', [])
    # 评分是第二个类名(索引为1),第一个类名总是`star-rating`
    rating = rating_class[1] if len(rating_class) > 1 else 'Unknown'

    # 数据清洗:去掉价格中的货币符号并转换为浮点数
    price_float = float(price[1:]) # 假设价格是如 ‘£51.77’ 的格式,去掉第一个字符£

    # 将清洗后的数据存入字典
    book_info = {
        'title': title,
        'price': price_float,
        'rating': rating
    }
    books_data.append(book_info)
    print(f"已提取:《{title}》 - 价格: £{price_float}, 评分: {rating}星")

第四步:数据存储与导出

抓取到的数据需要持久化存储,以便后续分析。将其保存为CSV文件是一种通用且方便的选择。

# 定义CSV文件名
csv_filename = 'books_data.csv'

# 写入CSV文件
with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
    fieldnames = ['title', 'price', 'rating']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    # 写入表头
    writer.writeheader()
    # 写入每一行数据
    for data in books_data:
        writer.writerow(data)

print(f"数据已成功保存到文件:{csv_filename}")

现在,在你运行代码的目录下,应该会生成一个名为books_data.csv的文件。你可以用Excel或任何文本编辑器打开它查看结果。

第五步:翻页抓取(进阶)

很多网站的数据分布在多个页面。观察目标网站,我们可以发现分页链接的规律(例如catalogue/page-2.html)。我们可以编写循环来抓取多页数据。

base_url = "http://books.toscrape.com/catalogue/page-{}.html"
all_books_data = []

# 假设我们要抓取前3页的数据
for page_num in range(1, 4):
    page_url = base_url.format(page_num)
    print(f"正在抓取第 {page_num} 页: {page_url}")
    # 重复步骤1-3的代码...(此处可封装成函数以保持代码整洁)
    # ... 将当前页的数据追加到 all_books_data 中 ...

print(f"共抓取 {len(all_books_data)} 条图书信息。")

代码示例:完整脚本

将以上所有步骤整合,得到一个更完整的、可运行的脚本。

import requests
from bs4 import BeautifulSoup
import csv
import time

def scrape_books_toscrape(num_pages=2):
    """抓取 books.toscrape.com 网站指定页数的图书信息"""
    base_url = "http://books.toscrape.com/catalogue/page-{}.html"
    all_books = []
    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'
    }

    for page in range(1, num_pages + 1):
        url = base_url.format(page)
        print(f"正在处理: {url}")

        try:
            response = requests.get(url, headers=headers, timeout=10)
            response.raise_for_status() # 如果状态码不是200,将引发异常
        except requests.exceptions.RequestException as e:
            print(f"请求页面 {url} 时出错: {e}")
            continue

        soup = BeautifulSoup(response.text, 'html.parser')
        books = soup.find_all('article', class_='product_pod')

        for book in books:
            title = book.h3.a['title']
            price = book.find('p', class_='price_color').text
            rating_class = book.find('p', class_='star-rating').get('class', [])
            rating = rating_class[1] if len(rating_class) > 1 else 'Unknown'
            price_float = float(price[1:])

            all_books.append({
                'title': title,
                'price': price_float,
                'rating': rating,
                'page': page
            })

        # 礼貌性延迟,避免给服务器带来过大压力
        time.sleep(1)

    return all_books

def save_to_csv(data, filename='books.csv'):
    """将数据保存到CSV文件"""
    with open(filename, 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=data[0].keys())
        writer.writeheader()
        writer.writerows(data)
    print(f"数据已保存至 {filename},共 {len(data)} 条记录。")

if __name__ == "__main__":
    books_data = scrape_books_toscrape(num_pages=3)
    if books_data:
        save_to_csv(books_data)

相关工具推荐

在进行爬虫开发和数据处理时,一些趁手的工具和设备能事半功倍:

  • 开发环境:除了前面提到的编辑器和笔记本,一台性能可靠的台式电脑对于需要长时间运行复杂爬虫任务的场景来说,是稳定之选。
  • 数据处理:对于抓取下来的大量数据,使用Pandas库在Python中进行分析是最佳实践。如果你的数据规模非常大,可能需要考虑数据库存储。
  • 学习资料:深入学习网络协议、HTML/CSS选择器以及反爬策略,可以参考《Python网络爬虫权威指南》等经典书籍。
  • 扩展工具:当目标网站是动态加载(使用JavaScript)时,requests+BeautifulSoup可能力不从心,这时你需要学习使用SeleniumPlaywright这样的浏览器自动化工具。

常见问题

  1. Q: 爬虫脚本被网站封禁了怎么办?
    A: 首先,检查你的请求频率是否过高,适当增加time.sleep()的延迟。其次,尝试轮换不同的User-Agent头部,或者使用代理IP池。始终遵守目标网站的robots.txt协议。

  2. Q: 网页内容是通过JavaScript动态加载的,BeautifulSoup抓不到怎么办?
    A: 这意味着你需要一个能执行JavaScript的“无头浏览器”。可以使用Selenium配合ChromeDriver,或Playwright,它们可以模拟完整的浏览器行为来获取渲染后的页面内容。

  3. Q: 抓取到的数据有乱码或缺失怎么处理?
    A:requests.get()时,可以尝试指定编码:response.encoding = 'utf-8'。数据缺失可能是因为定位选择器不准确,需要回到浏览器“检查元素”反复确认目标数据的准确路径。

  4. Q: 进行网络爬虫是否合法?
    A: 爬虫技术本身中立,但使用方式必须合法合规。务必遵守:

    • 遵守网站的robots.txt文件规定。
    • 控制请求频率,不影响目标网站正常运营。
    • 不抓取法律明确禁止的个人信息(如隐私数据)。
    • 尊重版权,不对受版权保护的内容进行非法抓取和使用。

总结

恭喜你!通过本教程,你已经掌握了使用Python进行网络爬虫开发的核心流程:发送请求 -> 解析页面 -> 提取数据 -> 存储结果。我们从一个简单的静态网页入手,实践了数据定位、清洗和存储的完整链路。网络爬虫是一个广阔而深入的领域,静态页面抓取只是起点。面对动态渲染网站、复杂反爬机制、海量数据分布式抓取等挑战,你需要不断学习新的工具(如Scrapy框架、Selenium)和策略。

记住,强大的能力伴随着责任。请始终将技术用于合法、正当的目的,并尊重他人的数据权益。现在,尝试修改我们的脚本,去抓取你感兴趣的其他网站数据吧!实践是最好的老师。如果在过程中遇到任何问题,回顾本教程的步骤和常见问题章节,或者查阅官方文档,通常都能找到解决方案。祝你在数据抓取的道路上一帆风顺!