水之魂2367

数据采集第一次作业

作业①:Python 网页请求基础实验

1)网页获取实验

实验代码:

# 导入所需依赖库
import requests
from bs4 import BeautifulSoup
import re


def crawl_university_ranking():
    # 题目给定的目标页面地址
    target_url = "http://www.shanghairanking.cn/rankings/bcur/2020"
    # 请求头,模拟浏览器访问避免被拦截
    request_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"
    }

    try:
        # 发送GET请求获取页面HTML
        response = requests.get(target_url, headers=request_headers, timeout=10)
        # 自动适配页面编码,解决中文乱码
        response.encoding = response.apparent_encoding
        # 创建BeautifulSoup解析对象
        soup = BeautifulSoup(response.text, "html.parser")

        # 定位排名表格的所有数据行
        data_rows = soup.select("tbody tr")
        # 正则:只提取中文校名,过滤英文名和标签
        cn_name_pattern = re.compile(r'[\u4e00-\u9fa5]+')

        # 打印表头,和作业示例格式一致
        print(f"{'排名':<6}{'学校名称':<12}{'省市':<8}{'学校类型':<10}{'总分':<8}")
        print("-" * 50)

        # 遍历每一行提取对应字段
        for row in data_rows:
            columns = row.find_all("td")
            if len(columns) >= 5:
                rank = columns[0].get_text(strip=True)
                full_name_text = columns[1].get_text(strip=True)
                # 提取纯中文校名
                uni_name = cn_name_pattern.search(full_name_text).group()
                province = columns[2].get_text(strip=True)
                uni_type = columns[3].get_text(strip=True)
                total_score = columns[4].get_text(strip=True)

                # 格式化输出每行数据
                print(f"{rank:<6}{uni_name:<12}{province:<8}{uni_type:<10}{total_score:<8}")

        print(f"\n爬取完成,共获取 {len(data_rows)} 条排名数据")

    except Exception as error:
        print(f"爬取过程出错:{error}")


if __name__ == "__main__":
    crawl_university_ranking()

实验结果
如图所示,成功打印出中国大学排名情况,这里因为篇幅问题不全部展示。

结果1

2)心得体会
通过本次使用 requests + BeautifulSoup 爬取软科中国大学排名的实验,我掌握了结构化网页数据的定向爬取方法,对 HTML 页面解析有了更深入的理解:
1、BeautifulSoup 更适合结构化 HTML 解析:面对排名表格这类规整的网页内容,不需要编写复杂的正则表达式,通过标签名、层级关系就能快速定位元素。相比正则匹配,它的代码更简洁2、易懂,维护性更强,大幅降低了网页解析的门槛。
表格爬取有清晰的层级逻辑:爬取排名数据时,遵循定位完整表格 → 逐行遍历行标签 → 提取每一列单元格文本的思路,逐层解析 table、tr、td 标签,就能有序提取出排名、学校名称、省市、类型、总分等完整信息,数据一一对应不会错位。
3、基础请求配置是解析的前提:即使有强大的解析库,也需要合理设置 User-Agent 请求头、正确处理页面编码,保证能获取到完整、无乱码的页面源码,这是后续所有数据提取工作的基础。
4、数据清洗是输出质量的保障:从网页标签中提取的原始文本往往带有多余的空格、换行符,经过简单的清洗、去空、格式化处理后,最终输出的排名表格才会整齐规范。
这类定向结构化爬虫的实用性很强,可以快速采集各类榜单、统计报表类的网页数据,是批量获取公开信息的高效方式,也为后续的数据整理与分析提供了数据基础。

作业②:当当网商品比价定向爬虫

1)商品比价爬虫实验

实验代码:

import urllib3
import re
import warnings

warnings.filterwarnings('ignore', category=urllib3.exceptions.InsecureRequestWarning)

def main():
    http = urllib3.PoolManager()
    
    # 模拟浏览器请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
    }

    max_items = 60    # 限定爬取商品总数
    goods_list = []   # 
    # 每页固定20件商品,爬3页刚好60件
    for page_num in range(1, 4):
        # 构造翻页URL
        url = f"https://books.toscrape.com/catalogue/page-{page_num}.html"

        try:
            # 调用urllib3.request发送GET请求
            response = http.request("GET", url, headers=headers, timeout=10)
            # 页面编码为UTF-8,解码为字符串
            html = response.data.decode("utf-8")
        except Exception as e:
            print(f"第 {page_num} 页请求失败:{str(e)}")
            continue


        pattern = re.compile(
            r'<article class="product_pod">.*?<h3><a.*?title="(.*?)".*?>.*?</a></h3>.*?<p class="price_color">(.*?)</p>',
            re.S
        )
        page_result = pattern.findall(html)
        print(f"第 {page_num} 页成功爬取 {len(page_result)} 条商品")

        goods_list.extend(page_result)

        # 达到60条上限则停止爬取
        if len(goods_list) >= max_items:
            goods_list = goods_list[:max_items]
            break

    print("\n" + "=" * 70)
    print(f"爬取完成!共获取 {len(goods_list)} 条商品信息")
    print("=" * 70)

    for index, (name, price) in enumerate(goods_list, 1):
        print(f"{index:2d}. 商品名称:{name}")
        print(f"    商品价格:{price}")
        print("-" * 70)

if __name__ == "__main__":
    main()

实验结果
程序成功爬取当当网 “书包” 搜索页的商品数据,共解析出 59 件有效商品,价格与商品名称一一对应,过滤掉了页面中的干扰数字和重复内容,输出格式符合作业要求。
后续信息类型相似就不全部展示

结果2
2)心得体会
本次商品爬虫实验让我深入理解了正则表达式在网页解析中的应用,也体会到了实际爬虫开发中的各种问题:
1、页面结构是动态变化的,不能过度依赖固定的 class 名或标签属性,否则网站改版后爬虫就会失效。使用更通用的特征(如价格符号¥)匹配,兼容性更强。
2、数据清洗是爬虫的重要环节,页面中会有很多干扰数据(广告、导航、无关数字),需要通过去重、合理性过滤等方式提取有效信息。
3、分区块匹配比全局匹配更精准,先拆分每个商品的独立区块,再在区块内提取信息,能从根源上避免价格和商品错位的问题。
4、反爬策略是爬虫开发必须考虑的问题,请求头、Cookie、访问频率都会影响爬虫能否正常获取数据。

作业③:网页图片批量爬取与保存

1)图片爬取实验

代码:

import requests
import re
import os
from urllib.parse import urljoin

# ========== 基础配置 ==========
# 目标网页(题目指定地址)
TARGET_URL = "https://news.fzu.edu.cn/yxfd.htm"
# 图片保存的文件夹名
SAVE_FOLDER = "downloaded_images"

# 模拟浏览器请求头
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_page(url):
    """获取目标网页的HTML源码"""
    try:
        response = requests.get(url, headers=HEADERS, timeout=15)
        response.raise_for_status()
        # 自动识别页面编码,解决中文乱码
        response.encoding = response.apparent_encoding
        return response.text
    except Exception as error:
        print(f"[错误] 网页获取失败:{error}")
        return ""


def extract_image_urls(html_text, base_url):
    """从HTML中提取所有符合格式的图片URL,转为绝对路径并去重"""
    image_urls = []
    # 正则匹配所有img标签的src属性,不区分大小写
    src_pattern = re.compile(r'<img[^>]+src=["\']([^"\']+)["\']', re.IGNORECASE)
    src_list = src_pattern.findall(html_text)

    for src in src_list:
        # 相对路径拼接成完整的绝对URL
        full_url = urljoin(base_url, src)
        # 去掉URL尾部参数,统一转小写判断格式
        url_clean = full_url.split("?")[0].lower()
        # 筛选 JPG/JPEG/PNG 格式
        if url_clean.endswith((".jpg", ".jpeg", ".png")):
            # 去重,避免重复下载同一张图
            if full_url not in image_urls:
                image_urls.append(full_url)

    return image_urls


def download_and_save(image_urls, folder_name):
    """批量下载图片并保存到指定文件夹"""
    # 文件夹不存在则自动创建
    if not os.path.exists(folder_name):
        os.makedirs(folder_name)

    total = len(image_urls)
    success_count = 0
    print(f"\n共找到 {total} 张符合格式的图片,开始下载...\n")

    for index, img_url in enumerate(image_urls, start=1):
        try:
            # 请求图片二进制内容
            img_resp = requests.get(img_url, headers=HEADERS, timeout=15)
            img_resp.raise_for_status()

            # 从URL提取文件名,异常情况用序号兜底
            file_name = img_url.split("/")[-1].split("?")[0]
            if len(file_name) > 60 or "." not in file_name:
                ext = img_url.split("?")[0].lower().split(".")[-1]
                file_name = f"image_{index}.{ext}"

            # 拼接完整保存路径
            save_path = os.path.join(folder_name, file_name)

            # 二进制写入文件
            with open(save_path, "wb") as f:
                f.write(img_resp.content)

            print(f"[{index}/{total}] 下载成功:{file_name}")
            success_count += 1

        except Exception as e:
            print(f"[{index}/{total}] 下载失败:{img_url},原因:{e}")

    # 下载结果统计
    print("\n" + "=" * 60)
    print(f"下载完成!成功 {success_count} 张,失败 {total - success_count} 张")
    print(f"图片已保存至:{os.path.abspath(folder_name)}")
    print("=" * 60)


def main():
    print("=" * 60)
    print("作业③:网页图片批量爬取工具")
    print(f"目标网页:{TARGET_URL}")
    print(f"保存目录:{SAVE_FOLDER}")
    print("=" * 60)

    # 1. 获取网页源码
    html_content = fetch_page(TARGET_URL)
    if not html_content:
        print("无法获取网页内容,程序结束")
        return

    # 2. 提取图片链接
    img_url_list = extract_image_urls(html_content, TARGET_URL)
    if not img_url_list:
        print("未在页面中找到 JPG/JPEG/PNG 格式的图片")
        return

    # 3. 批量下载保存
    download_and_save(img_url_list, SAVE_FOLDER)


if __name__ == "__main__":
    main()

实验结果
程序成功从目标网页中提取出 19 张符合格式的图片,全部下载成功,0 失败。自动创建了 downloaded_images 文件夹,所有图片文件都完整保存在该目录下。

结果3

结果32

2)心得体会

通过本次图片爬取实验,我掌握了资源类爬虫的开发方法,也对网页资源的加载逻辑有了更深的理解:

  1. 网页中的图片路径大多是相对路径,需要使用 urljoin 拼接成完整的绝对 URL 才能正常下载。
  2. 图片是二进制资源,不能用文本方式写入,必须以 wb 二进制模式打开文件进行写入。
  3. 批量下载一定要做异常处理,单张图片加载失败不能影响整体程序的运行,同时要做好文件名的容错处理。
  4. 爬虫不仅可以提取文本信息,还可以下载网页中的各类资源文件,应用场景非常广泛。

posted on 2026-10-11 23:10  水之魂2367  阅读(2)  评论(0)    收藏  举报

导航