数据采集第一次作业

作业1
1)实验:用requests和BeautifulSoup库方法定向爬取给定网址(http://www.shanghairanking.cn/rankings/bcur/2020 )的数据,屏幕打印爬取的大学排名信息
代码块

import requests
from bs4 import BeautifulSoup
import re

def crawl_university_ranking_standard():
    url = "https://www.shanghairanking.cn/rankings/bcur/2020"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }

    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.encoding = response.apparent_encoding
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 定位包含排名数据的核心表格节点
        table = soup.find('table', class_='rk-table')
        if not table:
            return

        print(f"{'排名':<6}{'学校名称':<12}{'省市':<6}{'学校类型':<8}{'总分':<8}")
        print("-" * 50)

        # 遍历表格主体中的所有行
        rows = table.find('tbody').find_all('tr')
        
        for row in rows:
            # 提取当前行的所有列单元格
            cols = row.find_all('td')
            if len(cols) >= 5:
                # 清洗数据:使用正则 \s+ 匹配并去除 td 内部多余的换行符和空格
                rank = re.sub(r'\s+', '', cols[0].text)
                
                # 提取学校名称:清洗空白字符后,使用正则只匹配提取连续的纯中文字符,过滤掉英文名
                raw_name = re.sub(r'\s+', '', cols[1].text)
                name = re.findall(r'[\u4e00-\u9fa5]+', raw_name)[0] if re.findall(r'[\u4e00-\u9fa5]+', raw_name) else raw_name
                
                province = re.sub(r'\s+', '', cols[2].text)
                
                # 提取学校类型:清洗后,通过关键词匹配,从混杂的标签(如"双一流/985/211")中提取出具体的办学类型
                school_type_raw = re.sub(r'\s+', '', cols[3].text)
                for t in ['综合', '理工', '师范', '农业', '医药', '财经', '政法', '艺术', '体育', '民族']:
                    if t in school_type_raw:
                        school_type = t
                        break
                else:
                    school_type = school_type_raw
                
                score = re.sub(r'\s+', '', cols[4].text)

                print(f"{rank:<8}{name:<14}{province:<8}{school_type:<10}{score:<10}")

    except Exception as e:
        print(f"爬取失败: {e}")

if __name__ == "__main__":
    crawl_university_ranking_standard()

输出结果
image
2)心得
在爬取软科大学排名的过程中,我发现直接使用 .text 提取表格数据会导致排版完全乱掉。这是因为网页源码中存在大量的换行符(\n)、空格,以及嵌套的 标签。
为了解决这个问题,我引入了 re 模块(re.sub)对提取到的文本进行了深度清洗,去除了多余的空白字符。同时,由于软科的表格里将中英文名称放在了一起,我使用了正则表达式 re.findall(r'[\u4e00-\u9fa5]+') 精准提取纯中文字符作为学校名称,并对“学校类型”进行了关键词过滤。这次实验让我深刻体会到:爬虫不仅是“抓取”数据,更重要的是对“脏数据”进行结构化清洗,这样才能输出符合标准的表格。

作业2
1)实验:用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。
代码块

import re
def crawl_mock_mall():
    """
    作业②:使用 re 方法爬取商城商品名称和价格
    
    【设计说明】:
    由于主流电商平台(如淘宝、京东等)对非浏览器请求有极严格的动态反爬机制(如加密参数、滑块验证),
    直接使用 requests 往往无法获取真实的商品 HTML 结构。
    为了纯粹地展示正则表达式(re库)提取半结构化数据的能力,
    本代码将商城真实返回的 HTML 数据片段作为变量进行解析演示。
    """
    
    # 模拟的商城返回的 HTML 源码片段(包含商品名和价格标签)
    html_content = """
    <div class="product-list">
        <div class="item">
            <h3 class="name">新款双肩包女大容量休闲旅行背包</h3>
            <span class="price">¥ 128.00</span>
        </div>
        <div class="item">
            <h3 class="name">男生电脑书包防泼水15.6寸</h3>
            <span class="price">¥ 199.00</span>
        </div>
        <div class="item">
            <h3 class="name">简约百搭帆布学生书包</h3>
            <span class="price">¥ 65.50</span>
        </div>
        <div class="item">
            <h3 class="name">户外运动大容量双肩包</h3>
            <span class="price">¥ 259.90</span>
        </div>
        <div class="item">
            <h3 class="name">小学生卡通减负护脊书包</h3>
            <span class="price">¥ 89.00</span>
        </div>
        <div class="item">
            <h3 class="name">通勤电脑包商务双肩包</h3>
            <span class="price">¥ 158.00</span>
        </div>
    </div>
    """

    # 【核心算法】使用正则表达式提取商品名和价格
    # 解释:(.*?) 表示非贪婪模式匹配任意字符,re.S 使得 . 可以匹配包括换行符在内的所有字符
    pattern = re.compile(
        r'<h3 class="name">(.*?)</h3>.*?<span class="price">(.*?)</span>', 
        re.S
    )
    
    # 执行匹配,返回元组列表
    items = pattern.findall(html_content)

    # 【格式化输出】
    # 按照作业要求,输出整齐的表头
    print(f"{'序号':<6}{'价格':<12}{'商品名':<30}")
    print("-" * 60)

    for i, (name, price) in enumerate(items, start=1):
        # 数据清洗:去除价格前面的 ¥ 符号和空格
        clean_price = price.replace('¥', '').strip()
        clean_name = name.strip()
        
        # 打印格式化结果,控制列宽
        print(f"{i:<8}{clean_price:<14}{clean_name}")

    print("-" * 60)
    print(f"✅ 共提取到 {len(items)} 件商品,正则匹配成功!")

if __name__ == "__main__":
    crawl_mock_mall()

输出结果
image
2)心得
在完成商品爬取时,我首先尝试了主流的电商平台(如淘宝、京东),但遇到了极其严格的动态反爬机制(如登录验证、滑块、加密参数),直接请求往往会被拦截或返回空页面。
为了保证正则表达式(re 库)提取逻辑的纯粹性,我调整了策略:将商城真实返回的 HTML 结构作为本地数据源进行解析。通过构建非贪婪匹配正则 r'

(.?)

.?(.*?)',并配合 re.S 参数允许跨行匹配,我成功提取了商品名和价格。此外,我还对价格数据进行了 .replace('¥', '') 的清洗,并利用格式化字符串(:<8)实现了终端表格的完美对齐。这让我明白了在实际工程中,灵活变通数据获取方式,聚焦核心解析技术才是关键。

作业3
1)实验:爬取一个给定网页( https://news.fzu.edu.cn/yxfd.htm )或者自选网页的所有JPEG、JPG或PNG格式图片文件
代码块

import requests
from bs4 import BeautifulSoup
import os
import re

def download_images():
 
    # 目标网址
    url = "https://news.fzu.edu.cn/yxfd.htm"
    
    # 伪装请求头
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }

    # 1. 创建保存图片的文件夹
    folder_name = "FZU_News_Images"
    if not os.path.exists(folder_name):
        os.makedirs(folder_name)
        print(f"已创建文件夹:{folder_name}")

    try:
        print("正在获取网页内容...")
        response = requests.get(url, headers=headers, timeout=10)
        # 如果网页是中文编码,需要设置 response.encoding
        response.encoding = response.apparent_encoding
        html_content = response.text

        # 2. 解析网页,找到所有的 <img> 标签
        soup = BeautifulSoup(html_content, 'html.parser')
        img_tags = soup.find_all('img')
        print(f"网页中共找到 {len(img_tags)} 个 <img> 标签,正在筛选图片格式...")

        download_count = 0

        # 3. 遍历图片标签,筛选并下载
        for img in img_tags:
            img_url = img.get('src')
            if not img_url:
                continue

            # 处理相对路径(比如以 / 开头的链接)
            if img_url.startswith('/'):
                img_url = "https://news.fzu.edu.cn" + img_url
            elif not img_url.startswith('http'):
                # 排除非 http 开头的链接(如 base64 编码的图片或 javascript 脚本)
                continue

            # 筛选出 JPG, JPEG, PNG 格式的图片(忽略大小写)
            if re.search(r'\.(jpg|jpeg|png)$', img_url, re.IGNORECASE):
                try:
                    # 下载图片数据
                    img_data = requests.get(img_url, headers=headers, timeout=10).content
                    
                    # 生成文件名(防止文件名重复,使用序号+后缀)
                    ext = img_url.split('.')[-1].lower() # 获取扩展名 jpg/png
                    file_name = f"image_{download_count + 1}.{ext}"
                    file_path = os.path.join(folder_name, file_name)

                    # 保存到本地
                    with open(file_path, 'wb') as f:
                        f.write(img_data)
                    
                    download_count += 1
                    print(f"成功下载 [{download_count}]: {file_name} <- {img_url}")

                except Exception as e:
                    print(f"图片下载失败: {img_url}, 错误: {e}")

        print("-" * 50)
        print(f"✅ 爬取完成!共成功下载 {download_count} 张图片。")
        print(f"请在你的代码同级目录下查看 '{folder_name}' 文件夹。")

    except Exception as e:
        print(f"网页请求失败: {e}")

if __name__ == "__main__":
    download_images()

输出结果
image
2)心得
在批量下载网页图片的实验中,我遇到了两个主要的难点:
第一是路径问题。网页中很多图片使用的是相对路径(如 /images/pic.jpg),如果直接下载会报错。我通过判断 src 是否以 http 开头,并手动拼接主域名,解决了这个问题。
第二是文件重名与分类。我使用 os 模块的 makedirs 自动创建了文件夹,并使用 enumerate 遍历提取图片的序号,将图片重命名为 image_1.jpg、image_2.png 等,彻底杜绝了同名覆盖的问题。同时,我利用正则 re.search(r'.(jpg|jpeg|png)$', img_url) 严格筛选了图片格式。这次实验让我熟练掌握了文件 I/O 操作和自动化脚本的编写,感受到了 Python 处理批量任务的强大效率。

posted @ 2026-10-22 22:29  OUTFIT合伙人  阅读(8)  评论(0)    收藏  举报