数据采集第一次作业
数据采集第一次作业
作业①:大学排名信息爬取
1. 代码与运行结果
实验要求
使用 requests 和 BeautifulSoup 库,定向爬取 2020 年中国大学排名页面,并在屏幕上打印大学排名信息。输出字段为:排名、学校名称、省市、学校类型、总分。
完整代码
import urllib.request
from bs4 import BeautifulSoup
headers = {
"User-Agent": "Mozilla/5.0"
}
def display_width(text):
width = 0
for char in text:
width += 2 if ord(char) > 127 else 1
return width
def align_text(text, width):
text = str(text)
return text + " " * max(0, width - display_width(text))
def get_data(url):
req = urllib.request.Request(url, headers=headers)
html = urllib.request.urlopen(req).read().decode("utf-8")
soup = BeautifulSoup(html, "html.parser")
rows = soup.find_all("tr")
universities = []
for row in rows:
cols = row.find_all("td")
if len(cols) >= 5:
data = [c.get_text(" ", strip=True) for c in cols]
if data[0].isdigit():
rank = data[0]
school = data[1].split(" ")[0]
province = data[2]
school_type = data[3]
score = data[4]
universities.append([
rank, school, province, school_type, score
])
return universities
url = "https://www.shanghairanking.cn/rankings/bcur/2020"
universities = get_data(url)
rank_width = 8
school_width = 24
province_width = 10
type_width = 12
print(
align_text("排名", rank_width) +
align_text("学校名称", school_width) +
align_text("省市", province_width) +
align_text("学校类型", type_width) +
"总分"
)
for university in universities:
rank, school, province, school_type, score = university
print(
align_text(rank, rank_width) +
align_text(school, school_width) +
align_text(province, province_width) +
align_text(school_type, type_width) +
score
)
运行结果

2. 心得体会
本次实验让我初步掌握了使用 requests 获取网页源代码、使用 BeautifulSoup 解析 HTML 文档的基本流程。通过查找表格和遍历表格行,可以将网页中原本以 HTML 形式组织的数据提取出来,再以较为整齐的格式打印到终端。
在实验过程中,我也认识到网页结构会直接影响解析结果。如果网页改版、表格结构发生变化,或者服务器限制了程序访问,就可能导致数据提取失败。因此,编写爬虫时不仅要关注数据解析,还要考虑请求异常、网页结构变化和结果检查等问题。
作业②:淘宝商城商品比价爬虫
1. 代码与运行结果
实验要求
使用 requests 和 re 库设计商城商品比价定向爬虫,以“书包”为关键词,提取商品名称和价格。
本次选择淘宝商城,原始搜索页面为:书包_淘宝搜索。

考虑到直接请求淘宝页面可能受到访问限制,且页面内容可能由 JavaScript 动态加载,为了便于实验和提高解析的稳定性,我先将该搜索网页下载到本地,再读取本地 HTML 文件进行解析。本题实际解析的是保存下来的网页文件,而不是每次运行时重新请求淘宝网站。
完整代码
将 taobao_spider.py 与 书包_淘宝搜索.html 放在同一个文件夹中,运行程序即可。
import re
import html
from pathlib import Path
# HTML文件路径
BASE_DIR = Path(__file__).resolve().parent
HTML_FILE = BASE_DIR / "书包_淘宝搜索.html"
# 读取本地HTML网页
def getHTMLText():
try:
with open(HTML_FILE, "r", encoding="utf-8",
errors="ignore") as f:
return f.read()
except FileNotFoundError:
print("错误:没有找到淘宝搜索结果HTML文件!")
return ""
except Exception as e:
print("读取网页失败:", e)
return ""
# 提取商品名称和价格
def parsePage(source):
goods_list = []
# 查找淘宝商品编号
pattern = r'id="item_id_(\d+)"'
matches = list(re.finditer(pattern, source))
for i, match in enumerate(matches):
start = match.start()
if i + 1 < len(matches):
end = matches[i + 1].start()
else:
end = len(source)
block = source[start:end]
# 提取商品名称
title_match = re.search(
r'class="title--[^"]*"\s+title="([^"]*)"',
block
)
# 提取价格整数部分
price_int_match = re.search(
r'class="priceInt--[^"]*">([^<]*)</div>',
block
)
# 提取价格小数部分
price_float_match = re.search(
r'class="priceFloat--[^"]*">([^<]*)</div>',
block
)
if not title_match or not price_int_match:
continue
name = html.unescape(title_match.group(1)).strip()
price_int = price_int_match.group(1).strip()
price_float = ""
if price_float_match:
price_float = price_float_match.group(1).strip()
try:
price = float(price_int + price_float)
except ValueError:
continue
if name:
goods_list.append({
"id": match.group(1),
"name": name,
"price": price
})
return goods_list
# 输出商品信息
def printGoods(goods_list):
print("\n" + "=" * 90)
print(" 淘宝商城商品比价结果")
print(" 搜索关键词:书包")
print("=" * 90)
print("{:<8}{:<18}{}".format(
"序号", "商品价格(元)", "商品名称"
))
print("-" * 90)
for i, goods in enumerate(goods_list, 1):
print("{:<8}{:<18.2f}{}".format(
i,
goods["price"],
goods["name"]
))
print("=" * 90)
print("成功获取商品数量:", len(goods_list), "项")
if goods_list:
print("商品最低价格:{:.2f}元".format(
min(g["price"] for g in goods_list)
))
print("商品最高价格:{:.2f}元".format(
max(g["price"] for g in goods_list)
))
print("商品平均价格:{:.2f}元".format(
sum(g["price"] for g in goods_list)
/ len(goods_list)
))
# 主函数
def main():
print("开始读取淘宝商城搜索结果")
print("搜索关键词:书包")
source = getHTMLText()
if not source:
return
print("网页读取成功!")
goods_list = parsePage(source)
print("网页解析完成!")
printGoods(goods_list)
print("\n实验任务完成!")
if __name__ == "__main__":
main()
运行结果

2. 心得体会
本次实验让我了解了正则表达式在网页信息提取中的应用。与直接输出整个网页相比,通过正则表达式匹配商品编号、名称和价格,可以将需要的信息从大量 HTML 代码中分离出来。
由于商品名称和价格位于同一商品对应的 HTML 数据块中,我先定位商品编号,再截取当前商品的数据范围,最后分别提取名称和价格。这种处理方式能够降低不同商品信息混淆的风险。
此外,本次实验采用本地 HTML 文件进行解析,使网页获取与数据提取两个步骤相互独立。这样既便于重复调试,也能减少频繁访问网站带来的不确定性。不过,本地网页只是保存时的页面快照,数据可能已经过时;如果淘宝页面的 HTML 结构发生变化,正则表达式也需要相应调整。
作业③:福州大学网页图片爬取
1. 代码与运行结果
实验要求
爬取福州大学院系风采页面 https://news.fzu.edu.cn/yxfd.htm 中的图片,将 JPEG、JPG 或 PNG 格式的图片文件保存到一个文件夹中。
完整代码
本程序使用 requests 获取网页和图片内容,使用 BeautifulSoup 解析图片标签,并根据图片 URL 的文件扩展名筛选目标图片格式。
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
from pathlib import Path
# 目标网页和图片保存目录
URL = "https://news.fzu.edu.cn/yxfd.htm"
SAVE_DIR = Path(__file__).resolve().parent / "fzu_images"
# 需要下载的图片格式
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png"}
def get_html(url):
"""请求目标网页并返回 HTML 文本。"""
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/128.0.0.0 Safari/537.36"
)
}
response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()
response.encoding = response.apparent_encoding
return response.text
def extract_image_urls(html_text, page_url):
"""解析网页,提取 JPEG、JPG 和 PNG 格式的图片链接。"""
soup = BeautifulSoup(html_text, "html.parser")
image_urls = set()
for image in soup.find_all("img"):
# 兼容常见的图片地址属性
candidates = [
image.get("src"),
image.get("data-src"),
image.get("data-original")
]
# 兼容 srcset 中提供的图片地址
srcset = image.get("srcset")
if srcset:
for item in srcset.split(","):
parts = item.strip().split()
if parts:
candidates.append(parts[0])
for candidate in candidates:
if not candidate:
continue
# 将相对地址转换为绝对地址
image_url = urljoin(page_url, candidate.strip())
path = urlparse(image_url).path.lower()
# 只保留题目要求的图片格式
if Path(path).suffix in IMAGE_EXTENSIONS:
image_urls.add(image_url)
return sorted(image_urls)
def download_images(image_urls):
"""下载图片并保存到指定文件夹。"""
SAVE_DIR.mkdir(parents=True, exist_ok=True)
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/128.0.0.0 Safari/537.36"
)
}
success_count = 0
with requests.Session() as session:
for index, image_url in enumerate(image_urls, start=1):
try:
response = session.get(
image_url, headers=headers, timeout=15
)
response.raise_for_status()
# 从 URL 中取得扩展名,避免保存成错误的格式
suffix = Path(urlparse(image_url).path).suffix.lower()
file_path = SAVE_DIR / f"image_{index:03d}{suffix}"
with open(file_path, "wb") as file:
file.write(response.content)
success_count += 1
print(f"已保存:{file_path.name}")
except requests.RequestException as error:
print(f"下载失败:{image_url}")
print("原因:", error)
print(f"\n网页中发现符合格式的图片链接:{len(image_urls)} 个")
print(f"成功下载图片:{success_count} 张")
print(f"图片保存目录:{SAVE_DIR}")
def main():
"""程序入口。"""
try:
html_text = get_html(URL)
image_urls = extract_image_urls(html_text, URL)
if not image_urls:
print("未找到符合要求的图片,请检查网页结构或图片地址。")
return
download_images(image_urls)
except requests.RequestException as error:
print("网页请求失败:", error)
if __name__ == "__main__":
main()
运行结果
运行程序后,程序会先解析网页中的图片地址,再依次下载符合格式要求的图片。成功下载的文件会保存在脚本所在目录下的 fzu_images 文件夹中,文件名按照 image_001.jpg、image_002.png 等形式生成。
程序会输出发现的图片链接数量、成功下载数量和保存目录。需要注意,发现的图片链接数不一定等于成功下载的图片数,因为部分图片可能无法访问,或者服务器可能限制请求。

图片文件夹截图:

2. 心得体会
本次实验让我掌握了网页图片爬取的基本流程:先请求网页,再解析图片标签,接着提取图片 URL,最后下载图片并保存到本地文件夹。
在处理图片链接时,需要注意相对路径与绝对路径的区别,因此使用 urljoin 将相对地址转换为完整 URL。同时,通过 urlparse 获取 URL 路径的扩展名,可以筛选出题目要求的 JPEG、JPG 和 PNG 格式图片。
实际网页中的图片不一定都能成功下载。例如,图片地址可能为空、图片资源可能失效,或者服务器拒绝访问。因此,程序对请求异常进行了处理,并分别统计发现的图片链接数量和实际下载成功的数量。
通过这三道题,我对 Python 爬虫的基本流程有了更完整的认识:获取网页、解析 HTML、提取目标数据以及保存结果。不同网页的结构各不相同,需要结合具体页面选择合适的解析方法,同时编写必要的异常处理代码,才能使程序更可靠。

浙公网安备 33010602011771号