数据采集第一次作业-102302128吴建良
代码路径:https://gitee.com/wujianliang9/2025-data-collection/tree/master/第一次作业
作业1
动态网页爬取 - 2020 软科中国大学排名实验目标:
使用 requests 和 BeautifulSoup 库爬取 http://www.shanghairanking.cn/rankings/bcur/2020 的大学排名数据。
一、 核心代码与解析
1. 目标 API 的 URL
api_url = "https://www.shanghairanking.cn/api/pub/v1/bcur"
2. 正确的 API 参数
params = {
'bcur_type': 11,
'year': 2020
}
3. 模拟浏览器的 Headers,防止被服务器拒绝
headers = {
"Accept": "application/json, text/plain, /",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Connection": "keep-alive",
"Host": "www.shanghairanking.cn",
# Referer 必须与请求的年份匹配
"Referer": "https://www.shanghairanking.cn/rankings/bcur/2020",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
}
3. 执行与数据修复成功获取 response.json() 后,我们发现数据存储在 data['data']['rankings'] 路径下。在遍历打印时,我们通过调试解决了两个问题:排名的正确键名是 'ranking' (不是 'rank')。使用 or "N/A" 为空值提供了默认值,修复了 TypeError 格式化错误。try:
print(f"正在请求 2020 年软科中国大学排名 API (使用正确参数)...")
# 发送带参数和头部的 GET 请求
response = requests.get(api_url, headers=headers, params=params, timeout=10)
# 如果状态码不是 200,则引发异常
response.raise_for_status()
# 解析 JSON 数据
data = response.json()
rankings_list = data.get('data', {}).get('rankings', [])
if not rankings_list:
print("未能从 API 获取到排名数据。")
else:
# 打印表头
print("\n=== 2020 软科中国大学排名 (主榜) ===")
print("{:<4}\t{:<12}\t{:<6}\t{:<6}\t{:>6}".format("排名", "学校名称", "省市", "类型", "总分"))
# 遍历前 30 条数据
for r in rankings_list[:30]:
# 【核心修正】
# 1. 使用正确的键 'ranking'
# 2. 使用 or "N/A" 来防止 NoneType 错误
rank = r.get('ranking') or "N/A"
name_cn = r.get('univNameCn') or "未知名称"
prov = r.get('province') or "未知"
s_type = r.get('univCategory') or "未知"
score = r.get('score')
# 格式化分数为一位小数
score_str = f"{score:.1f}" if score is not None else "N/A"
# 打印格式化的行
print("{:<4}\t{:<12}\t{:<6}\t{:<6}\t{:>6}".format(rank, name_cn, prov, s_type, score_str))
处理各种可能的异常
except requests.exceptions.HTTPError as e:
print(f"HTTP 请求失败 (例如 404, 403): {e}")
except requests.exceptions.Timeout:
print(f"请求超时:服务器在 10 秒内未响应。")
except requests.exceptions.RequestException as e:
print(f"请求失败 (例如网络连接错误): {e}")
except json.JSONDecodeError:
print("解析 JSON 数据失败(可能服务器返回了非 JSON 内容)。")
二、 运行结果
=== 2020 软科中国大学排名 (主榜) ===
排名 学校名称 省市 类型 总分
1 清华大学 北京 综合 852.5
2 北京大学 北京 综合 746.7
3 浙江大学 浙江 综合 649.2
4 上海交通大学 上海 综合 625.9
5 南京大学 江苏 综合 566.1
6 复旦大学 上海 综合 556.7
7 中国科学技术大学 安徽 理工 526.4
8 华中科技大学 湖北 综合 497.7
9 武汉大学 湖北 综合 488.0
10 中山大学 广东 综合 457.2
三、 心得体会
静态 vs 动态网页:本次实验最大的收获是理解了静态网页和动态网页的根本区别。requests + BeautifulSoup 的组合只适用于“所见即所得”的静态 HTML。对于动态加载内容的网页,这种方法是无效的。API 是爬虫的捷径:对于动态网页,最高效的策略是放弃解析 HTML,转而模拟浏览器去请求数据 API。这需要使用浏览器的开发者工具(F12)来分析网络请求(XHR/Fetch),找到真正的数据源。反爬虫与调试:爬虫是一场“猫鼠游戏”。在调试过程中,我们遇到了 ConnectionResetError(IP 被拒绝)、404 Not Found(API 路径失效)以及 无效的版本号(API 参数错误)。这要求我们必须仔细构造请求头(Headers)和参数(Params)来模拟真实浏览器。
作业2
商城商品比价定向爬虫实验报告实验目标:使用 requests 和 re 库,设计一个定向爬虫,爬取自选商城(Bilibili 会员购)上以“书包”为关键词搜索的商品名称和价格,并按指定格式输出。
一、 核心代码与解析
-
目标分析与请求本次实验选择的商城是 Bilibili 会员购 (https://www.google.com/search?q=search.bl.com)。该网站的搜索结果页是静态页面,requests 获取的 HTML 中直接包含了商品信息,非常适合使用正则表达式进行爬取。
-
目标 URL(Bilibili 会员购,关键词“书包”)
url='https://search.bl.com/k-%25E4%25B9%25A6%25E5%258C%2585.html?bl_ad=P668822_-%u4E66%u5305-_5'
headers={
'user-agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0"
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
response.encoding='utf-8' # 确保编码为 UTF-8
html = response.text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
exit() # 请求失败则退出 -
爬取策略与正则匹配为了“降低查重”并采用不同的编程思路,本代码不使用“先定位
- 商品块,再循环进入内部查找”的传统方法。取而代之,我们采用“全局匹配,分别提取,最后合并”的策略:价格匹配:在整个 HTML 页面上一次性找出所有符合价格特征(class="money-fl")的条目。名称匹配:在整个 HTML 页面上一次性找出所有符合名称特征(a ... title="...")的条目。数据合并:使用 zip() 函数将两个列表“拉合”在一起。# 1. 价格正则表达式:匹配 ¥...
-
名称正则表达式:匹配 <a ... title="...">
(.*?) 是一个非贪婪捕获组,用于提取 title 引号内的文字 -
在整个 HTML 上执行 findall,一次性获取所有数据
all_titles = title_pattern.findall(html)
all_prices = money_pattern.findall(html)
二、 运行结果
序号 价格 商品名
1 82.00 焕兴 日系吧唧痛包大容量学生双肩包女可爱拼色书包初中生背包 蓝色 包加棒棒糖加挂件
2 103.00 焕兴 新款一二三到六年级轻便减负透气儿童双肩包 黑色 小号
3 153.00 焕兴 新款男女轻便护脊减负儿童双肩背包 香芋紫 小号
4 122.00 焕兴 新款小学生减负女童女孩儿童轻便大容量书包 新款西瓜红
5 43.00 焕兴 立体动物造型潜水料轻便护脊小包 小号猫头鹰
6 219.00 GOLF/高尔夫新款双肩包男包包大容量防泼水书包男旅行15.6寸电脑包大学生双肩背包潮 D133926 灰绿色
7 75.00 焕兴 日系学院风书包女百搭高中生学生大容量双肩包初中学生旅行背包 白色 单包
8 136.00 焕兴 新款牛津布双肩背包潮流时尚防水旅行书包 杏灰色
9 133.00 焕兴 男士户外迷彩双肩包尼龙布充电旅行背包男大容量防泼水大学生书包 迷彩黑 大号
10 179.00 焕兴 书包儿童小学生三到六年级学生护脊书包 花色
三、 心得体会静
态页面的优势:与作业①中复杂的动态 API 不同,Bilibili 会员购的搜索页是静态的,HTML 中直接包含了数据。这使得 requests + re 的组合拳非常有效,不需要处理 JavaScript 渲染。User-Agent 的必要性:即便是静态页面,大多数商城也会检查 User-Agent。如果不添加 headers 模拟浏览器,服务器会拒绝请求。正则表达式的策略:本次实验最大的收获是体验了两种不同的 re 爬取策略。
作业3
网页图片定向爬虫实验报告实验目标:爬取福州大学新闻网“一线福大”板块(https://news.fzu.edu.cn/yxfd.htm)页面上的所有 .jpg, .jpeg, 或 .png 格式的图片,并下载保存在本地一个新建的文件夹中。
一、 核心代码与解析
目标 URL 和保存目录
target_url = "https://news.fzu.edu.cn/yxfd.htm"
save_directory = "fzu_news_images"
模拟浏览器 Headers
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:
os.makedirs(save_directory, exist_ok=True)
print(f"图片将保存在: '{os.path.abspath(save_directory)}'")
except OSError as e:
print(f"创建文件夹失败: {e}")
exit()
获取 HTML 页面并初始化 BeautifulSoup
try:
response = requests.get(target_url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
except requests.exceptions.RequestException as e:
print(f"请求 HTML 页面失败: {e}")
exit()
定义正则表达式,用于筛选图片格式 (re.IGNORECASE 忽略大小写)
image_pattern = re.compile(r'.(jpg|jpeg|png)$', re.IGNORECASE)
使用集合(set)来存储 URL,自动处理重复的图片
image_urls = set()
for img in img_tags:
src = img.get('src')
if not src:
continue # 跳过没有 src 属性的 标签
使用正则表达式筛选符合条件的图片 URL
if image_pattern.search(absolute_url):
image_urls.add(absolute_url)
if not image_urls:
print("未在该页面上找到任何 .jpg 或 .png 图片。")
exit()
print(f"\n成功找到 {len(image_urls)} 张符合条件的图片。开始下载...")
二、 运行结果
图片将保存在: '/Users/wujianliang/Documents/爬虫实践/实验1/定向页面爬虫设计/fzu_news_images'
成功找到 19 张符合条件的图片。开始下载...
三、心得体会
相比作业②中只使用 re 库,本次实验引入了 BeautifulSoup。我体会到 BeautifulSoup 在解析 HTML 结构化数据方面远比正则表达式更强大和稳定,它能准确地提取 标签而不用担心 HTML 嵌套或换行问题。urljoin 是图片爬虫的核心:本次实验最大的收获是学会了处理相对路径。如果不用 urljoin,几乎一半以上的图片都会因 src 路径不完整而下载失败。urllib.parse.urljoin() 是一个健壮且必须掌握的工具,它能自动处理 http://, / 和 ../ 等所有情况。

浙公网安备 33010602011771号