数据采集第一次作业

bzy1

数据采集与融合技术 第一次作业

作业①

实验

实验目标:使用 requests + BeautifulSoup 定向爬取软科2020中国大学排名页面,控制台输出:排名、学校名称、省市、学校类型、总分
目标URL:http://www.shanghairanking.cn/rankings/bcur/2020
依赖安装:pip install requests beautifulsoup4 lxml

import requests
from bs4 import BeautifulSoup

def get_html_text(url: str):
    """
    发起网页请求,获取页面HTML文本,处理反爬、异常、编码
    :param url: 目标网页链接
    :return: html字符串,失败返回空
    """
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": "zh-CN,zh;q=0.9"
    }
    try:
        # 增加超时,防止卡死
        resp = requests.get(url, headers=headers, timeout=25)
        resp.raise_for_status()
        resp.encoding = "utf-8"
        return resp.text
    except requests.exceptions.HTTPError as he:
        print(f"HTTP访问错误:{he}")
        return ""
    except Exception as e:
        print(f"页面请求异常:{e}")
        return ""


def parse_university_rank(html: str):
    """
    解析软科排名页面,提取 排名、校名、省市、学校类型、总分
    :param html: 网页源码
    :return: 列表,每一项是一所学校信息
    """
    soup = BeautifulSoup(html, "lxml")
    # 定位数据表格主体
    table_body = soup.find("tbody")
    if not table_body:
        print("未找到数据表格tbody标签!")
        return []
    rows = table_body.find_all("tr")
    res_list = []
    for row in rows:
        tds = row.find_all("td")
        # 校验单元格数量,防止页面结构变动报错
        if len(tds) >= 5:
            rank = tds[0].get_text(strip=True)
            school_name = tds[1].get_text(strip=True)
            province = tds[2].get_text(strip=True)
            school_kind = tds[3].get_text(strip=True)
            score = tds[4].get_text(strip=True)
            res_list.append([rank, school_name, province, school_kind, score])
    return res_list


if __name__ == "__main__":
    target_url = "http://www.shanghairanking.cn/rankings/bcur/2020"
    html_content = get_html_text(target_url)
    data = parse_university_rank(html_content)

    # 格式化打印,和题目样例格式对齐
    print(f"{'排名':<6}{'学校名称':<18}{'省市':<8}{'学校类型':<10}{'总分':<8}")
    for item in data:
        print(f"{item[0]:<6}{item[1]:<18}{item[2]:<8}{item[3]:<10}{item[4]:<8}")

bzy2

心得体会
本次定向静态爬虫实验,目标页面是软科2020中国大学排名。一开始踩坑点:软科网站有基础反爬,不带User-Agent直接访问会403拒绝;之前版本没有校验td单元格长度,页面部分行结构不一样,会出现下标越界。
我理解了静态网页爬虫的标准流程:构造请求头伪装浏览器、获取源码、BeautifulSoup定位tbody主体、循环遍历tr行提取td单元格。
通过这个实验,我区分了strip()去除空白换行的作用,学会增加异常捕获提升鲁棒性;同时明白爬虫要遵守robots协议,控制访问频率,仅用于课程学习,不高频批量请求给网站造成负担。静态解析适合结构固定、不使用JS渲染的页面,是数据采集最基础的手段。


作业②

bzy1-1

实验
实验目标:requests + re正则表达式(禁止bs4),商城比价爬虫,搜索关键词“书包”,提取【序号、价格、商品名称】
选择京东搜索页(稳定性强,适合正则抓取)
依赖:只需要requests

import requests
import re

def get_page_source(url: str):
    """获取网页源码文本"""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
    }
    try:
        r = requests.get(url, headers=headers, timeout=25)
        r.raise_for_status()
        r.encoding = "utf-8"
        return r.text
    except Exception as e:
        print(f"商城页面请求失败:{e}")
        return ""

def parse_goods_by_re(html: str):
    """
    纯正则匹配:商品名称、商品价格,不使用BeautifulSoup
    非贪婪匹配 .*? 防止跨标签抓取错误
    """
    # 匹配京东商品价格
    pattern_price = re.compile(r'<em class="J_price">¥<span>(\d+\.?\d*)</span></em>')
    # 匹配商品标题
    pattern_title = re.compile(r'<a target="_blank" title="(.*?)" href')
    price_result = pattern_price.findall(html)
    title_result = pattern_title.findall(html)
    # 两个列表打包对齐
    goods_data = list(zip(title_result, price_result))
    return goods_data


if __name__ == "__main__":
    search_url = "https://search.jd.com/Search?keyword=书包"
    page_html = get_page_source(search_url)
    goods = parse_goods_by_re(page_html)
    print(f"{'序号':<6}{'价格':<8}{'商品名'}")
    for idx, (title, price) in enumerate(goods, start=1):
        print(f"{idx:<6}{price:<8}{title}")

心得体会
本实验和上一个实验最大区别:放弃标签解析库,使用正则表达式直接在原始字符串里匹配内容。写正则的时候很容易踩贪婪匹配的坑,一开始写.*会一口气匹配到很远的结束标签,改成.*?非贪婪模式才可以精准捕获。
正则适合页面标签简单、结构固定的场景,缺点非常明显:网站前端只要修改class名字、调整标签顺序,整个正则直接失效,兼容性弱。而BeautifulSoup依靠标签层级,容错更好。比价爬虫的思路可以拓展,同时爬取多个电商平台,实现横向比价;但是一定要控制请求间隔,避免IP封禁。这次也加深了我对字符串匹配、正则分组捕获的理解。


作业③

bzy1-3

实验
实验目标:爬取福大新闻页面 https://news.fzu.edu.cn/yxfd.htm ,抓取所有jpg/jpeg/png图片,自动新建文件夹保存图片,过滤其他格式
依赖:requests、beautifulsoup4

import requests
from bs4 import BeautifulSoup
import os
from urllib.parse import urljoin

def get_html(url: str):
    """请求页面源码"""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
    }
    try:
        resp = requests.get(url, headers=headers, timeout=20)
        resp.raise_for_status()
        resp.encoding = "utf-8"
        return resp.text
    except Exception as e:
        print(f"福大新闻页面请求失败:{e}")
        return ""

def download_image(img_link: str, save_folder: str):
    """
    下载单张图片,只保留 jpg / jpeg / png
    :param img_link: 图片完整url
    :param save_folder: 保存文件夹名称
    """
    try:
        img_resp = requests.get(img_link, timeout=15)
        # 获取后缀小写,统一判断
        suffix = img_link.split(".")[-1].lower()
        if suffix not in ["jpg", "jpeg", "png"]:
            return
        img_filename = os.path.basename(img_link)
        save_full_path = os.path.join(save_folder, img_filename)
        # 图片是二进制,wb模式写入
        with open(save_full_path, "wb") as f:
            f.write(img_resp.content)
        print(f"✅ 已保存图片:{img_filename}")
    except Exception as e:
        print(f"❌ 图片下载失败 {img_link},错误:{e}")


if __name__ == "__main__":
    page_url = "https://news.fzu.edu.cn/yxfd.htm"
    save_dir_name = "fzu_news_pic"
    # 文件夹不存在就自动创建
    if not os.path.exists(save_dir_name):
        os.mkdir(save_dir_name)
    html_text = get_html(page_url)
    soup = BeautifulSoup(html_text, "lxml")
    img_tags = soup.find_all("img")
    for img in img_tags:
        src = img.get("src")
        if not src:
            continue
        # 重点:网页内很多src是相对路径,urljoin拼接成完整绝对地址,否则404
        absolute_img_url = urljoin(page_url, src)
        download_image(absolute_img_url, save_dir_name)
    print("\n==== 全部图片处理完毕 ====")

心得体会
图片采集和文本采集有很大区别:文本读取resp.text,图片必须读取二进制的resp.content,以wb二进制模式写入本地文件。这个页面大量图片是相对路径,是本次最大难点,如果不使用urljoin拼接,直接拿src去请求,全部404访问失败。
同时我增加了后缀过滤,严格只保存题目指定的JPG/JPEG/PNG。课程实验仅用于学习网页多媒体采集;图片本身存在版权,不可以商用传播。这个实验让我掌握了资源类爬虫的思路,也理解了url相对路径、绝对路径的转换逻辑。

整体总结
三次爬虫实验覆盖了静态文本解析、正则匹配、二进制资源下载三类典型数据采集场景,分别练习BeautifulSoup标签解析、re正则表达式、图片资源爬取,掌握请求头伪装、异常捕获、路径拼接、编码处理这些通用爬虫基础知识点。

posted @ 2026-10-22 20:37  崔jj  阅读(9)  评论(0)    收藏  举报