数采实践—第一次作业

Editor 赖彦然
学号 102402106
My Gitee https://gitee.com/Vivian_azad/lyr.git

作业任务目录:

① 爬取软科中国大学排名(requests + BeautifulSoup)
② 商城"书包"商品比价定向爬虫(requests + re)
③ 批量爬取网页图片并保存(requests + re)


三个作业遵循同一套爬虫基本流程:

graph LR A[确定目标网址] --> B[requests 发送请求] B --> C[获取网页源码] C --> D{选择解析方式} D -->|结构化标签| E[BeautifulSoup 解析] D -->|文本特征匹配| F[re 正则提取] E --> G[打印或保存结果] F --> G

一、爬取软科中国大学排名(主要考察:requests + BeautifulSoup)

1.1 作业代码与运行结果

爬取目标:软科中国大学排名2020,提取排名、学校名称、省市、学校类型、总分并打印。

实现思路:

  1. requests 携带请求头访问目标页面;
  2. BeautifulSoup 定位 class 为 rk-table 的排名表格;
  3. 遍历表体中每一行 tr,按列取出文本,用制表符对齐打印。

代码1:

# editor:Lai Yanran
# 2026年10月12日

import csv
import requests
from bs4 import BeautifulSoup

# 软科中国大学排名2020
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/120.0.0.0 Safari/537.36"
}

# 发送get请求获取网页
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = "utf-8"

# 用BeautifulSoup解析网页
soup = BeautifulSoup(resp.text, "html.parser")

# 找到排名表格
table = soup.find("table", class_="rk-table")

"""
考虑到结果的可读性,在这里,我选择把结果写成csv表格文件,这样可以方便地用Excel打开查看。在实际应用中,也会更方便后续的研究
"""

# 一条条把表格里的数据取出来,存进列表
rows = []
for tr in table.find("tbody").find_all("tr"):
    tds = tr.find_all("td")
    rank = tds[0].get_text(strip=True)          # 排名
    name = tds[1].find("span", class_="name-cn").get_text(strip=True)  # 学校名称
    province = tds[2].get_text(strip=True)      # 省市
    school_type = tds[3].get_text(strip=True)   # 学校类型
    score = tds[4].get_text(strip=True)         # 总分
    rows.append([rank, name, province, school_type, score])

# 把结果写成csv表格文件
# 用utf-8-sig编码,这样用Excel打开不会乱码
with open("大学排名.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["排名", "学校名称", "省市", "学校类型", "总分"])  
    writer.writerows(rows) 

#打印一条代码运行完成的提示
print(f"爬取成功啦!!共{len(rows)}条数据,已保存到大学排名.csv")


运行结果(csv文件截图,生成文件已经和代码一起上传):

image

运行结果截图:
7fc831eb38401a82ef4b14c9e13851c2

💡 关键点:学校中文名并不直接在 td 里,而是单独包裹在 class="name-cn" 的 span 中,需要在第二个 td 里再向下找一层,直接取 td 文本会混入排名数字等杂项。

1.2 作业心得

这次作业让我完整走了一遍爬虫的基本流程:requests 发请求、拿到网页文本、再用 BeautifulSoup 解析。体会最深的是,写解析代码前一定要先按 F12 打开开发者工具观察网页结构:排名数据在一个 class 为 rk-table 的表格里,每行是 tr,每列是 td,找到这些规律后代码就很好写了。

另外还有两个小收获:一是请求时要带上 User-Agent 模拟浏览器,这是爬虫的基本常识,很多网站会拦截没有请求头的访问;二是 get_text(strip=True) 可以把标签里的文本取出来并去掉多余空白,比手动处理字符串方便很多。



二、商城商品比价定向爬虫(requests + re)

2.1 作业代码与运行结果

爬取目标:选择当当网[^2],以关键词"书包"搜索,用正则提取商品名称和价格并打印。

实现思路:

  1. 关键词按 gb2312 编码后拼出搜索页 URL;
  2. requests 获取搜索结果页源码(注意设置响应编码防乱码);
  3. 用 re 正则分别匹配商品名和价格,按序号对齐打印。

代码2:

# editor:Lai Yanran
# 2026年10月12日

import re
import requests
from urllib.parse import quote

# 选择当当网,搜索关键词"书包"
keyword = "书包"

# 当当网的搜索关键词要用gb2312编码拼到网址里,这是由于网站机制
url = "http://search.dangdang.com/?key=" + quote(keyword.encode("gb2312"))

#请求头
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"
}

# 发送get请求获取搜索页面
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = "gb18030"  # 当当网页是gb2312编码,不设置会乱码
html = resp.text

# 用正则提取商品名和价格
# 商品名在a标签的title属性里,价格数字在price_n标签里
names = re.findall(r'<p class="name" name="title"[^>]*><a title="([^"]+)"', html)
prices = re.findall(r'<span class="price_n">&yen;(.*?)</span>', html)

# 把商品名和价格配对存到列表里
goods = []
count = min(len(names), len(prices))
for i in range(count):
    name = names[i].strip()
    price = float(prices[i].strip())
    goods.append([price, name])

"""
由于结果众多,所以我模拟了许多人平时的购物习惯,按价格从低到高排序,只取价格最低的前20名商品输出,这样更符合实际应用场景
"""

# 按价格从低到高排序,只取价格最低的前20名
goods.sort(key=lambda x: x[0])
top20 = goods[:20]

# 打印表头
print("序号\t价格\t商品名")

# 逐条打印价格最低的前20名商品
for i in range(len(top20)):
    price = top20[i][0]
    name = top20[i][1]
    print(f"{i + 1}\t{price:.2f}\t{name}")

print(f"\n共爬取到{count}个商品,已按价格从低到高输出前{len(top20)}名")

运行结果截图:

image

2.2 作业心得

这次作业比作业一难,主要卡在两个地方。第一个是编码问题:当当网用的是 gb2312 编码,搜索关键词要先 encode("gb2312") 再 quote 才能拼出正确的网址,拿到响应后也要设置 resp.encoding = "gb18030",不然打印出来全是乱码。

第二个是正则的编写,我一开始照着渲染后的页面结构写,结果一个都匹配不到,后来改为对照网页源代码逐段排查,才定位到商品名在 a 标签的 title 属性里、价格数字在 price_n 标签里。这让我明白正则没有捷径,核心就是反复观察目标文本的前后特征。另外用 min(len(names), len(prices)) 取两个列表的较小长度,可以避免商品名和价格数量不一致时索引越界报错。



三、爬取网页图片(requests + re)

3.1 作业代码与运行结果

爬取目标:福州大学新闻网页中所有 JPEG、JPG、PNG 格式的图片,统一保存到 3_images 文件夹。

实现思路:

  1. requests 获取网页源码,用 apparent_encoding 自动识别编码;
  2. 正则匹配所有 src 中后缀为 jpg / jpeg / png 的图片地址;

代码3:

# editor:Lai Yanran
# 2026年10月12日

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

# 福州大学新闻网页
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/120.0.0.0 Safari/537.36"
}


# 创建保存图片的文件夹
save_dir = "3_images"
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

# 发送get请求获取网页
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = resp.apparent_encoding
html = resp.text

# 正则找出所有jpg、jpeg、png格式的图片地址
img_srcs = re.findall(r'src="([^"]+\.(?:jpg|jpeg|png))"', html, re.I)
print(f"找到{len(img_srcs)}张图片")

count = 0
for src in img_srcs:
    img_url = urljoin(url, src)
    ext = os.path.splitext(img_url.split("?")[0])[1]
    try:
        # 下载图片并保存到文件夹
        img_data = requests.get(img_url, headers=headers, timeout=10).content
        file_path = os.path.join(save_dir, f"{count + 1}{ext}")
        with open(file_path, "wb") as f:
            f.write(img_data)
        print(f"已保存:{file_path}")
        count += 1
    except Exception as e:
        print(f"{img_url} 下载失败:{e}")

print("已经下载了%d张图片,保存在%s文件夹中" % (count, save_dir))


运行结果截图(控制台输出 + 保存图片的文件夹):
image
image

测试一下,图片是否都能正常打开

屏幕录制 2026-10-12 191943

3.2 作业心得

这次作业让我学会了爬取并保存二进制文件。和爬文本不同,下载图片要用 response.content 拿到二进制内容,写文件时也要用 "wb" 二进制写入模式。正则部分用 (?:jpg|jpeg|png) 同时匹配三种格式,加上 re.I 忽略大小写,因为网页里的图片后缀写法不统一。

最容易踩的坑是相对路径:网页里很多图片的 src 是类似 /_upload/... 这样的相对地址,直接拿去请求会报错,需要用 urljoin 把相对路径补全成完整 URL。另外我还加了 try/except,这样个别图片下载失败时程序不会整体崩溃,而是跳过继续下载下一张;保存前先用 os.path.exists 判断文件夹是否存在,避免重复建目录报错。


总结

三个task对比,用到的技术各有侧重:

作业 目标网站 解析方式 最难的一点
① 大学排名 软科 BeautifulSoup 多层标签的逐层定位
② 商品比价 当当网 re 正则 gb2312 编码与原始 HTML 结构确认
③ 图片下载 福州大学新闻网 re 正则 相对路径补全与二进制保存

通过这次作业,我对"发送请求 → 获取源码 → 解析提取 → 输出保存"这条爬虫主线有了完整的实践。

posted @ 2026-10-12 19:35  Vivian_azad  阅读(17)  评论(0)    收藏  举报