作业1

网络数据爬取作业实践报告

作业一:大学排名信息爬取实践

1.1 作业代码与运行结果

核心代码
def get_university_ranking():
    """
    爬取软科中国大学排名数据
    """
    # 目标URL
    url = "http://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/91.0.4472.124 Safari/537.36'
    }

    try:
        # 发送HTTP请求
        response = requests.get(url, headers=headers)
        response.encoding = 'utf-8'

        # 检查请求是否成功
        if response.status_code == 200:
            # 使用BeautifulSoup解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')

            # 查找排名表格
            table = soup.find('table', {'class': 'rk-table'})

            if table:
                # 提取表格数据
                data = []
                rows = table.find('tbody').find_all('tr')

                for row in rows:
                    row_data = []
                    cells = row.find_all('td')

                    for i, cell in enumerate(cells):
                        text = cell.get_text().strip()

                        # 如果是学校名称列(通常是第2列),只提取前面的汉字部分
                        if i == 1:  # 学校名称列
                            # 使用正则表达式只匹配汉字,遇到非汉字字符就停止
                            chinese_name = re.match(r'^[\u4e00-\u9fa5]+', text)
                            if chinese_name:
                                text = chinese_name.group()
                            else:
                                # 如果没有匹配到汉字,使用原始文本的前几个字符
                                text = text[:10]  # 限制长度

                        row_data.append(text)

                    data.append(row_data)

                # 打印表格
                print("\n" + "=" * 80)
                print("中国大学排名(2020年)")
                print("=" * 80)

                # 打印表头
                print(f"{'排名':<8} {'学校名称':<12} {'省市':<8} {'学校类型':<10} {'总分':<10}")
                print("-" * 80)

                # 打印数据(前20条)
                for i, row in enumerate(data[:20]):
                    if len(row) >= 5:
                        rank = row[0]
                        name = row[1]
                        province = row[2] if len(row) > 2 else ""
                        school_type = row[3] if len(row) > 3 else ""
                        score = row[4] if len(row) > 4 else ""

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

                print("-" * 80)
                print(f"共爬取 {len(data)} 条数据")

                return data
            else:
                print("未找到排名表格")
                return None

        else:
            print(f"请求失败,状态码: {response.status_code}")
            return None

    except Exception as e:
        print(f"爬取过程中出现错误: {e}")
        return None

image

1.2 作业心得与体会

通过本次实践,我深入掌握了网页数据爬取的核心技术流程。在实现过程中,特别体会到BeautifulSoup库在HTML解析方面的强大功能,其简洁的API设计大大提高了开发效率。同时,对网页编码问题的处理也有了更深刻的理解,认识到正确设置编码对于中文网页数据提取的重要性。

作业二:商城商品比价爬虫实现

2.1 作业代码与运行结果

核心代码

def get_pdd_products():
    """
    爬取拼多多书包商品信息
    """
    # 搜索关键词
    keyword = "书包"

    # 拼多多搜索URL(移动端页面,结构相对简单)
    url = "https://mobile.yangkeduo.com/search_result.html"

    # 请求参数
    params = {
        'search_key': keyword,
        'page': 1
    }

    # 设置请求头,模拟手机浏览器
    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Accept-Encoding': 'gzip, deflate, br',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1'
    }

    try:
        # 发送HTTP请求
        response = requests.get(url, params=params, headers=headers, timeout=10)
        response.encoding = 'utf-8'

        print(f"请求状态码: {response.status_code}")
        print(f"响应内容长度: {len(response.text)}")

        if response.status_code == 200:
            html_content = response.text

            # 方法1:尝试从JSON数据中提取商品信息
            # 拼多多通常会将数据放在window.rawData中
            json_pattern = r'window\.rawData\s*=\s*({.*?});'
            json_match = re.search(json_pattern, html_content, re.DOTALL)

            if json_match:
                try:
                    json_data = json_match.group(1)
                    data = json.loads(json_data)
                    print("成功提取JSON数据")
                    return parse_json_data(data)
                except json.JSONDecodeError as e:
                    print(f"JSON解析失败: {e}")

            # 方法2:如果JSON提取失败,使用正则表达式从HTML中提取
            print("尝试使用正则表达式提取...")
            return parse_html_with_regex(html_content)

        else:
            print(f"请求失败,状态码: {response.status_code}")
            return None

    except requests.exceptions.Timeout:
        print("请求超时,请检查网络连接")
        return None
    except Exception as e:
        print(f"爬取过程中出现错误: {e}")
        return None


def parse_json_data(data):
    """
    从JSON数据中解析商品信息
    """
    products = []

    try:
        # 尝试不同的JSON路径来查找商品数据
        stores = data.get('stores', {})
        goods_list = stores.get('goodsList', [])

        if goods_list:
            for goods in goods_list:
                try:
                    price = goods.get('normalPrice', '')
                    name = goods.get('goodsName', '')
                    if price and name:
                        products.append((price, name))
                except:
                    continue

        # 如果上面没找到,尝试其他路径
        if not products:
            items = data.get('items', [])
            for item in items:
                try:
                    price = item.get('price', '')
                    name = item.get('name', '')
                    if price and name:
                        products.append((price, name))
                except:
                    continue

    except Exception as e:
        print(f"解析JSON数据失败: {e}")

    return products


def parse_html_with_regex(html_content):
    """
    使用正则表达式从HTML中提取商品信息
    """
    products = []

    try:
        # 尝试匹配商品信息
        # 模式1:匹配价格和商品名
        pattern1 = r'"normalPrice":"(\d+\.?\d*)".*?"goodsName":"([^"]*)"'
        matches1 = re.findall(pattern1, html_content)

        # 模式2:匹配常见的商品展示格式
        pattern2 = r'¥(\d+\.?\d*).*?>(.*?)<'
        matches2 = re.findall(pattern2, html_content)

        # 模式3:匹配更简单的格式
        pattern3 = r'(\d+\.?\d*)元.*?([\u4e00-\u9fa5a-zA-Z0-9]+书包[\u4e00-\u9fa5a-zA-Z0-9]*)'
        matches3 = re.findall(pattern3, html_content)

        # 合并所有匹配结果
        all_matches = matches1 + matches2 + matches3

        for match in all_matches:
            if len(match) >= 2:
                price = match[0]
                name = match[1]
                # 清理名称
                name = re.sub(r'<[^>]+>', '', name)
                name = name.replace('\\', '').strip()

                # 只保留包含"书包"关键词的商品
                if '书包' in name:
                    products.append((price, name))

        # 去重
        unique_products = list(set(products))

    except Exception as e:
        print(f"正则表达式解析失败: {e}")

    return unique_products


image

2.2 作业心得与反思

本次作业让我对正则表达式在文本提取中的应用有了全新认识。虽然正则表达式学习曲线较陡峭,但其在复杂文本模式匹配方面具有不可替代的优势。通过反复调试优化,最终实现了高精度的数据提取模式。

作业三:网页图片资源爬取

3.1 作业代码与运行结果

代码
import requests
import os
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import time


def download_images(url, save_folder='downloaded_images'):
    """
    爬取网页中的所有图片并保存到本地文件夹
    """
    # 创建保存图片的文件夹
    if not os.path.exists(save_folder):
        os.makedirs(save_folder)

    # 设置请求头
    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'
    }

    try:
        # 发送HTTP请求
        response = requests.get(url, headers=headers)
        response.encoding = 'utf-8'

        if response.status_code == 200:
            # 使用BeautifulSoup解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')

            # 查找所有图片标签
            img_tags = soup.find_all('img')

            # 支持的图片格式
            valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']

            downloaded_count = 0

            print("\n" + "=" * 60)
            print("开始下载图片...")
            print("=" * 60)

            for i, img in enumerate(img_tags, 1):
                # 获取图片URL
                img_url = img.get('src') or img.get('data-src')

                if img_url:
                    # 处理相对URL
                    img_url = urljoin(url, img_url)

                    # 检查图片格式
                    parsed_url = urlparse(img_url)
                    img_path = parsed_url.path.lower()

                    # 检查是否为支持的图片格式
                    is_valid_image = any(img_path.endswith(ext) for ext in valid_extensions)

                    if is_valid_image:
                        try:
                            # 下载图片
                            img_response = requests.get(img_url, headers=headers, timeout=10)

                            if img_response.status_code == 200:
                                # 生成文件名
                                img_name = os.path.basename(parsed_url.path)
                                if not img_name or '.' not in img_name:
                                    img_name = f"image_{i}.jpg"

                                # 保存图片
                                file_path = os.path.join(save_folder, img_name)

                                # 如果文件名已存在,添加数字后缀
                                counter = 1
                                original_name = img_name
                                while os.path.exists(file_path):
                                    name, ext = os.path.splitext(original_name)
                                    img_name = f"{name}_{counter}{ext}"
                                    file_path = os.path.join(save_folder, img_name)
                                    counter += 1

                                with open(file_path, 'wb') as f:
                                    f.write(img_response.content)

                                downloaded_count += 1
                                print(f"✓ 已下载: {img_name}")

                                # 添加短暂延迟,避免请求过快
                                time.sleep(0.1)

                        except Exception as e:
                            print(f"✗ 下载失败: {img_url} - 错误: {e}")
                            continue

            print("=" * 60)
            print(f"图片下载完成!共下载 {downloaded_count} 张图片")
            print(f"图片保存在: {os.path.abspath(save_folder)}")

            return downloaded_count
        else:
            print(f"请求失败,状态码: {response.status_code}")
            return 0

    except Exception as e:
        print(f"爬取过程中出现错误: {e}")
        return 0


# 主程序
if __name__ == "__main__":
    # 使用给定的URL或自选URL
    target_url = "https://news.fzu.edu.cn/yxfd.htm"

    print("开始爬取网页图片...")
    download_images(target_url)

image

3.3 作业心得与总结

本次作业让我全面掌握了网络资源下载的技术要点。特别是在文件流操作、本地存储管理和批量下载优化方面积累了宝贵经验。对HTTP请求响应过程的理解也更加深入。

posted on 2025-10-15 16:06  安眠吧  阅读(31)  评论(0)    收藏  举报

导航